Type inference in ruby

T

Trevor Andrade

------=_NextPart_000_0000_01C4F589.389CC7A0
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: 7bit

Hello all,

I was wondering whether it would be possible to have a type inference system
in ruby. My question was asked before
<http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/95821> by
gabriele renzi but it never received much of a response. This system might
try to figure out whether you are writing code with some obvious errors.
There has been a <http://www.cc.gatech.edu/~lex/ti/ti.html> project on this
for smalltalk. For instance if you have a function like the following



def foo(object)

return object.call(9, 7, 3)

end



couldn't the type system figure out that object must respond to the call
command and thus eliminate an error like:



foo(5)



I guess I am also wondering about a lot of other things like why do you need
multiple assignment in Ruby? There doesn't seem to be any need for it since
you can just modify an object by sending it a message eg x = x + 1 is the
same as x.+(1). I am not sure if this would help type inference systems but
it seems like it should. There is a <http://rubyforge.org/projects/truby/>
ruby project that is trying to create a type inference system although it is
very experimental. Can people give some examples where type inference would
be very difficult in Ruby? Does anybody know what kinds of things make it
difficult to do type inference in a language. On the smalltalk type
inference project site they say the following



"Type inference in Smalltalk-like languages has been studied since at least
1981, when Norihisa Suzuki published a type inference algorithm for
Smalltalk-80. Chuck's algorithm DDP is unusual, however, in two ways: it is
demand-driven and prunes subgoals. A demand-driven algorithm is architected
around the notion of "goals", where each goal is either answered directly
("what is the type of 47?"), or via subgoals ("what is the type of x+y?").
The advantage of this approach is that, whenever too many goals are being
studied, it is possible to "prune" some of the goals by giving them obvious
but poor answers ("the type could be anything"); the analysis can then
procede, and it may still find good answers to other questions. Pruning in
this fashion does not appear possible in the competing approaches of
abstract interpretation and of constraint solving; such approaches must
completely solve any subproblems they generate."



It seems like a system like this would be good for Ruby because it would
allow you to catch some errors and maybe even do some optimizations if you
were making a compiler since you would know the representations of some of
the objects.



Regards,

Trevor Andrade


------=_NextPart_000_0000_01C4F589.389CC7A0--
 
E

Eric Anderson

Trevor said:
I was wondering whether it would be possible to have a type inference system
in ruby. My question was asked before

I am sure it is possible to implement but I think most people end up
wondering why do it? If you want a typed system (strong or weak) there
are plenty of languages that support it natively. For me that is one of
the reasons I left those other languages. For me a type system has too
much coding overhead without much benefit. The two advantages are:

* Catches type errors
* Possibly better optimizations

To answer the first advantage Ruby encourages Unit testing. Unit testing
it 10 times better than type checking because it can not only check for
valid types but also check for logic errors. So why spend the overhead
of a type system when unit testing is better.

The second advantage again isn't an issue for me. Ruby is fast enough.
If I need it faster I can profile the code to find bottlenecks. If I
need it even faster I can recode the bottlenecks in C. Again, the
overhead of a type system is not worth even the possibility of better
optimizations.

Just my two cents,

Eric
 
L

Logan Capaldo

There doesn't seem to be any need for it since
you can just modify an object by sending it a message eg x = x + 1 is the
same as x.+(1).
Minor correction, x = x + 1 IS not the same as x.+(1), its the same as
x = x.+(1). + is non-destructive, (well assuming this isn;t a user
defined or modified object).
 
J

James Britt

Trevor said:
Hello all,

I was wondering whether it would be possible to have a type inference system
in ruby. My question was asked before
<http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/95821> by
gabriele renzi but it never received much of a response. This system might
try to figure out whether you are writing code with some obvious errors.
There has been a <http://www.cc.gatech.edu/~lex/ti/ti.html> project on this
for smalltalk. For instance if you have a function like the following

<snip/>

I don't want to dismiss this question, but is there a reference or
archive page for the "static typing (quasi and otherwise)" permathread?

Also, some links that may be of interest:

"Adding Optional Static Typing to Python"
http://www.artima.com/weblogs/viewpost.jsp?thread=85551

"Adding Optional Static Typing to Python -- Part II"
http://www.artima.com/weblogs/viewpost.jsp?thread=86641

"DSL Design Considerations"
http://home.comcast.net/~bc19191/blog/050105.html

The last one is quite interesting in the way it makes you think about
language design, and how what feature and syntax you do or don't provide
effects usage and language evolution.

James
 
A

Alexander Kellett

rade said:
def foo(object)
return object.call(9, 7, 3)
end

couldn't the type system figure out that object must respond to the
call
command and thus eliminate an error like:

foo(5)

i see no difficulty in using ruby's advanced tracing
facilities to improve documentation and via persistant
storage of such api metadata also adding an "early warning"
system. or rather, not so much early warnings, but more much
more obvious error messages as opposed to wierd 'ugh ur meant
to quack!' style messages ;)

unfortunately i don't have the time :(
I guess I am also wondering about a lot of other things like why do
you need
multiple assignment in Ruby? There doesn't seem to be any need for it
since
you can just modify an object by sending it a message eg x = x + 1 is
the
same as x.+(1). [snip]

multiple return values and multiple assignment just fit well together
imho :)
without it i'd almost certainly be forced to fork the interpreter :p

i'd be very interested in type inference for
another reason:
intelligent code completion
with tooltips offering details on
method documentation and param/return value
typing expectations

greetings,
Alex
 
T

Trevor Andrade

Let me just point out that I am NOT ADVOCATING STATIC TYPING. I don't think
ruby should force users to static type. I am also not advocating any
changes whatsoever to the language Ruby with one exception and that is
multiple assignment which I don't see any need for. I could, of course, be
wrong and if anybody knows a good example where multiple assignment makes
things easier I could easily be persuaded that it is useful. I guess the
only reason for preserving multiple assignment that I can think of is to
preserve idioms like x = x + 1 which as pointed out is different from
x.+(1). You could of course make x = x + 1 translate into x.+(1) as a bit
of syntactic sugar but that might lead to other problems. Type inference is
something that would exist in the interpreter as some kind of error
messages. You could turn it off if necessary. I think that in most cases
it would be helpful in that it would catch real errors and I believe
although I can't prove this that any ruby program at all no matter how
dynamic would pass through the type inference system without any error
provided it did not have any statement that if executed would lead to an
error of the form "NoMethodError: undefined method 'foo' for someobject".
This of course is the error you get when you call a method on an object that
does not have that method defined.

In a dynamic language like Ruby errors of the form I alluded to above are
the only type errors that I believe are in general possible. I have a very
simple model for object oriented language like Ruby which is probably wrong
but I think ultimately captures the gist of things. In Ruby or Smalltalk
you can only essentially do one thing and that is send messages to objects.
Everything in Ruby consists of essentially message passing. Thus the only
error possible is that an object does not know how to respond to a message.
Of course my model is not completely correct because ultimately in any
language you have to actually "do something" at some point. For instance if
you want to add 2 numbers or concatenate a string that is "doing something"
and not just message passing. However the "doing something" part of Ruby
and Smalltalk only exists either at the lowest levels of the language that
are built in or in extensions to the language written in c. You cannot
define how to add integers in Ruby and in fact you cannot even define
integers themselves. Integers are low level constructs that must be built
into the language. You can still even do type inference at this low level
because the number of low level object are finite and the built in
operations you can do with them are already defined like for instance adding
integers or concatenating strings. So it always known that you can't add an
integer to a string and this can always produce an error before runtime
which currently does not happen. For instance you can run the following in
ruby and it is valid

def ass(blah)
q = 4 + "fjdkjkf"
end

and I this error will be caught only at runtime.

There is only one thing wrong with type inference and that is that new
methods can be defined at runtime in Ruby which means it is possible that an
object does not know how to respond at compile time to a message but it does
know how to respond at runtime. However I think this scenario happens very
rarely and if it was happening the programmer could just turn off type
inference.
 
T

Trevor Andrade

I was just wondering how do they fit together? Are you talking about
multiple assignment as in:

X = 1
X = 2

Or as in

X, Y = foo(blah)

Where foo is define as

def foo()
return 1, 2
end

I think was a bit ambiguous in my email so let me make myself clear. The
term multiple assignment is used in two situation or at least I use it in
two situations. In one situation a variable is assigned to and then
assigned to again. In the other situation, two variable are assigned to at
the same time. Both these situations are called multiple assignment. I am
referring to the first situation. I believe you are referring to the
second. I have no problem with the second situation. It is the first that
I believe is unnecessary. Unless I am missing something and the two kinds
of multiple assignment are some how related.
 
A

Alexander Kellett

I think was a bit ambiguous in my email so let me make myself clear.
The
term multiple assignment is used in two situation or at least I use it
in
two situations. In one situation a variable is assigned to and then
assigned to again. In the other situation, two variable are assigned
to at
the same time. Both these situations are called multiple assignment.
I am
referring to the first situation. I believe you are referring to the
second. I have no problem with the second situation. It is the first
that
I believe is unnecessary. Unless I am missing something and the two
kinds
of multiple assignment are some how related.

i can't really explain.
but it just feels right.
maybe the ruth/ast will help u see why:
irb(main):003:0> Ruby.parse 'def mult_ret; return 1, 5; end'
=> Def[:mult_ret, [], Return[ArrayLiteral[[IntegerLiteral[1],
IntegerLiteral[5]]]]]
and
irb(main):007:0> Ruby.parse 'a, b = nil, nil'
=> Masgn[ArrayLiteral[[LocalAssign[:a, nil], LocalAssign[:b, nil]]],
nil, ArrayLiteral[[NilLiteral[], NilLiteral[]]]]
(notice the use of ArrayLiteral as return and ArrayLiteral in
multi-assign)

for a more concrete and useful example.
consider this:
a, b = b, a

Alex
 
A

Alexander Kellett

I think was a bit ambiguous in my email so let me make myself clear.
The
term multiple assignment is used in two situation or at least I use it
in
two situations. In one situation a variable is assigned to and then
assigned to again. In the other situation, two variable are assigned
to at
the same time. Both these situations are called multiple assignment.
I am
referring to the first situation. I believe you are referring to the
second. I have no problem with the second situation. It is the first
that
I believe is unnecessary. Unless I am missing something and the two
kinds
of multiple assignment are some how related.

having reread this i must say i'm greatly confused
why would anyone want to use
x = 1
x = 2
?
or u mean constants in particular?
a very confused Alex ;)
 
A

Alexander Kellett

You cannot define how to add integers in Ruby and in fact you cannot
even define
integers themselves. Integers are low level constructs that must be
built
into the language. [snip]

its possible to redefine integer additions in ruby.
however yes you're correct in saying that its not possible
to redefine the integer constructor. (tho i'm working
on making that possible ;))
There is only one thing wrong with type inference and that is that new
methods can be defined at runtime in Ruby which means it is possible
that an
object does not know how to respond at compile time to a message but
it does
know how to respond at runtime. However I think this scenario happens
very
rarely and if it was happening the programmer could just turn off type
inference.

i think personally that test suites should guide typing metadata.
if a testcase only has a test for a single data type. then the
assumption can be made that the type itself is required. if however
it has a test for two different data types each of which have a given
method, which happens to be part of an included module, to ease test
case writing it should be possible via comment hints to show the
inferrer / document-type-metadata-hinter that it is duck typed not
static typed.

Alex
 
T

Trevor Andrade

That example was just intended to demonstrate the difference between the two
definition of multiple assignment. I wasn't meant to do something..

-----Original Message-----
From: Alexander Kellett [mailto:[email protected]]
Sent: Saturday, January 08, 2005 5:20 PM
To: ruby-talk ML
Subject: Re: Type inference in ruby

I think was a bit ambiguous in my email so let me make myself clear.
The
term multiple assignment is used in two situation or at least I use it
in
two situations. In one situation a variable is assigned to and then
assigned to again. In the other situation, two variable are assigned
to at
the same time. Both these situations are called multiple assignment.
I am
referring to the first situation. I believe you are referring to the
second. I have no problem with the second situation. It is the first
that
I believe is unnecessary. Unless I am missing something and the two
kinds
of multiple assignment are some how related.

having reread this i must say i'm greatly confused
why would anyone want to use
x = 1
x = 2
?
or u mean constants in particular?
a very confused Alex ;)
 
T

Trevor Andrade

In this case I did not mean redefine integers and integer addition I meant
define in the first place. What I was trying to say is that if you had no
built in construct in Ruby of integers then there would be absolutely no way
in which to define integers or integer addition in Ruby. You would have to
make a c extension to the language. Of course it is possible to redefine
integers but that is not what I was talking about.

What I was originally trying to get at is that there are only 2 things you
do in Ruby 1) send messages to objects 2) Perform built in operations on
built on things like integers and strings. In 1) you are not really doing
anything instead you are sending messages to objects and telling them to do
things. In 2) you are doing something like adding integers, concatenating
strings, displaying output, getting input etc. Type checking for 1)
involves checking if an object can accept a certain kind of message. Type
checking for 2) is more involved and depends on the built-in types
themselves, like for instance the fact that you can't add a string to an
integer although you can add a float to an integer. Even for 2) type
inference is still possible because there are only a finite number of built
in constructs and their properties are known. Of course if you add in new c
extensions to the language then these cannot be checked. However I don't
think type checking has to be exhaustive or strong.

-----Original Message-----
From: Alexander Kellett [mailto:[email protected]]
Sent: Saturday, January 08, 2005 5:26 PM
To: ruby-talk ML
Subject: Re: Type inference in ruby

You cannot define how to add integers in Ruby and in fact you cannot
even define
integers themselves. Integers are low level constructs that must be
built
into the language. [snip]

its possible to redefine integer additions in ruby.
however yes you're correct in saying that its not possible
to redefine the integer constructor. (tho i'm working
on making that possible ;))
There is only one thing wrong with type inference and that is that new
methods can be defined at runtime in Ruby which means it is possible
that an
object does not know how to respond at compile time to a message but
it does
know how to respond at runtime. However I think this scenario happens
very
rarely and if it was happening the programmer could just turn off type
inference.

i think personally that test suites should guide typing metadata.
if a testcase only has a test for a single data type. then the
assumption can be made that the type itself is required. if however
it has a test for two different data types each of which have a given
method, which happens to be part of an included module, to ease test
case writing it should be possible via comment hints to show the
inferrer / document-type-metadata-hinter that it is duck typed not
static typed.

Alex
 
M

Mark Firestone

I'm writing a fido mail tosser for my ruby bbs. (A thankless task that
is far worse than I ever imagined when I started.) and I have a problem
I don't understand.

To read the packets (the header in this case, I have to do the
following, is it is stored in an odd way. Here's a snippet of the file
header...

PPÔ
(and lots of other low ascii characters...)

So, I read it like this, suck in a bunch of it in a buffer...

buffer = happy.read(0x3a)

orgnode = (buffer[0x01] << 8) + buffer[0x00]
destnode = (buffer[0x03] << 8) + buffer[0x02]
orgnet = (buffer[0x15] << 8) + buffer[0x14]
destnet = (buffer[0x17] << 8) + buffer[0x16]
orgzone = (buffer[0x23] << 8) + buffer[0x22]
destzone = (buffer[0x25] << 8) + buffer[0x24]

and so on. This works great, we get the right answer...

if I try to reverse this and write stuff, it doesn't work. For
example...

happy = File.new("#{path}", File::CREAT|File::APPEND|File::RDWR, 0644)

buffer = []

buffer[0x00] = (f_hdr.orgnode & 0x00ff)
buffer[0x01] = ((f_hdr.orgnode & 0xff00) >> 8)
buffer[0x02] = (f_hdr.destnode & 0x00ff).chr
buffer[0x03] = ((f_hdr.destnode & 0xff00) >> 8)
buffer[0x04] = ((f_hdr.year + 1900) & 0x00ff)
buffer[0x05] = (((f_hdr.year + 1900) & 0xff00) >> 8)
buffer[0x06] = f_hdr.month
buffer[0x08] = f_hdr.day
buffer[0x0a] = f_hdr.hour

and so on and then...

happy.write buffer

I get a string of numbers. If I try to put .chr at the end, the first
two values read ok, then it goes haywire. I don't think I understand
what I'm doing. Can anyone point me in the right direction?

Thanks!

Mark
 
C

Charles Mills

Mark said:
I'm writing a fido mail tosser for my ruby bbs. (A thankless task that
is far worse than I ever imagined when I started.) and I have a problem
I don't understand.

To read the packets (the header in this case, I have to do the
following, is it is stored in an odd way. Here's a snippet of the file
header...

PPÔ
(and lots of other low ascii characters...)

So, I read it like this, suck in a bunch of it in a buffer...

buffer = happy.read(0x3a)

orgnode = (buffer[0x01] << 8) + buffer[0x00]
destnode = (buffer[0x03] << 8) + buffer[0x02]
orgnet = (buffer[0x15] << 8) + buffer[0x14]
destnet = (buffer[0x17] << 8) + buffer[0x16]
orgzone = (buffer[0x23] << 8) + buffer[0x22]
destzone = (buffer[0x25] << 8) + buffer[0x24]

and so on. This works great, we get the right answer...

if I try to reverse this and write stuff, it doesn't work. For
example...

happy = File.new("#{path}", File::CREAT|File::APPEND|File::RDWR, 0644)

buffer = []

should this be:
buffer = ''
buffer[0x00] = (f_hdr.orgnode & 0x00ff)
buffer[0x01] = ((f_hdr.orgnode & 0xff00) >> 8)
buffer[0x02] = (f_hdr.destnode & 0x00ff).chr
buffer[0x03] = ((f_hdr.destnode & 0xff00) >> 8)
buffer[0x04] = ((f_hdr.year + 1900) & 0x00ff)
buffer[0x05] = (((f_hdr.year + 1900) & 0xff00) >> 8)
buffer[0x06] = f_hdr.month
buffer[0x08] = f_hdr.day
buffer[0x0a] = f_hdr.hour

and so on and then...

happy.write buffer
(...)
Sounds like you should be using String#unpack and Array#pack.

-Charlie
 
G

gabriele renzi

James Britt ha scritto:
<snip/>

I don't want to dismiss this question, but is there a reference or
archive page for the "static typing (quasi and otherwise)" permathread?

Also, some links that may be of interest:

"Adding Optional Static Typing to Python"
http://www.artima.com/weblogs/viewpost.jsp?thread=85551

"Adding Optional Static Typing to Python -- Part II"
http://www.artima.com/weblogs/viewpost.jsp?thread=86641

notice there is a part III too:
http://www.artima.com/weblogs/viewpost.jsp?thread=87182
and some comments on matz' blog that I could not decipher :)
 
F

Florian Gross

Trevor said:
def foo(object)

return object.call(9, 7, 3)

end
couldn't the type system figure out that object must respond to the call
command and thus eliminate an error like:

foo(5)

class Fixnum
def call(*args) end
end

Note that Ruby could not even insert a check at the beginning of the
method as another Thread might dynamically define Fixnum#call.
I guess I am also wondering about a lot of other things like why do you need
multiple assignment in Ruby? There doesn't seem to be any need for it since
you can just modify an object by sending it a message eg x = x + 1 is the
same as x.+(1).

I don't see the connection between the two and you are not even doing
multiple assignment in your example.

Fixnum#+ does not modify the original receiver. It returns the result as
a new Object. There are in place modifications in Ruby (String#gsub!
etc.), but that has nothing to do with multiple assignment.
 
P

Premshree Pillai

I am sure it is possible to implement but I think most people end up
wondering why do it? If you want a typed system (strong or weak) there
are plenty of languages that support it natively. For me that is one of

Your sentence seems ambiguous. What exactly do you mean by it? _All_
languages are either strong typed or weak typed.
the reasons I left those other languages. For me a type system has too

I think that's the same reason most people love dynamic languages like
Python and Ruby. Both of them are also strong typed. I like that.
However, a lot of people favor static typing. There has been
discussion going around to implement optional static typing in Python.
There's also pychecker (http://pychecker.sf.net/) for Python for
syntax error checking and stuff that wouldn't have been caught by the
interpreter itself. Wonder if there's something like this for Ruby.
:-w
 
G

gabriele renzi

Premshree Pillai ha scritto:
Your sentence seems ambiguous. What exactly do you mean by it? _All_
languages are either strong typed or weak typed.




I think that's the same reason most people love dynamic languages like
Python and Ruby. Both of them are also strong typed. I like that.
However, a lot of people favor static typing. There has been
discussion going around to implement optional static typing in Python.
There's also pychecker (http://pychecker.sf.net/) for Python for
syntax error checking and stuff that wouldn't have been caught by the
interpreter itself. Wonder if there's something like this for Ruby.
:-w

well, a guy did CheckR as its thesis, IIRC, but nothing has been
published as far as I know.
 
L

Lothar Scholz

Hello Alexander,


AK> i see no difficulty in using ruby's advanced tracing
AK> facilities to improve documentation and via persistant

Rubys tracing facilities are far away from being advanced.
Tracing type information is (for performance reasons) almost
impossible on real world programs.
 
A

Austin Ziegler

Hello all,

I was wondering whether it would be possible to have a type
inference system in ruby. My question was asked before
<http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/95821>
by gabriele renzi but it never received much of a response. This
system might try to figure out whether you are writing code with
some obvious errors. There has been a
<http://www.cc.gatech.edu/~lex/ti/ti.html> project on this for
smalltalk. For instance if you have a function like the following

def foo(object)
return object.call(9, 7, 3)
end

couldn't the type system figure out that object must respond to
the call command and thus eliminate an error like:

foo(5)

I'm not sure what you're trying to say here; are you wanting the
parser to detect errors like this? I'm not sure that's the right
place; sure Fixnum doesn't have a virtual class, but you can do
this:

class Fixnum
def call(*args)
puts args.join("|")
end
end

This then totally screws up your type inference. There's no way to
be certain -- at parsing time -- that a particular call would be
invalid.

I guess I am also wondering about a lot of other things like why
do you need multiple assignment in Ruby? There doesn't seem to be
any need for it since you can just modify an object by sending it
a message eg x = x + 1 is the same as x.+(1).

Multiple assignment? Do you mean:
x, y = y, x

Or do you mean specifically:
x = x + 1

As far as your statement is concerned,
x = x + 1

is NOT the same as:
x.+(1)

It's the same as:
x = x.+(1)

There is a distinct and important difference here.

In Ruby -- the language proper -- type inference won't really help,
at least IMO. In an interpreter or compiler for Ruby, it could make
a difference.

-austin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top