[comp.compilers] Static type-checking with dynamic scoping

Chuck_Lins.SIAC_QMAIL@gateway.qm.apple.com (Chuck Lins) (01/16/91)

[in <3818@cernvax.cern.ch> roberto@cernvax.cern.ch (roberto bagnara) asks]
roberto> is it possible to do static type-checking when
roberto> you've [got] dynamic binding?

Unless I seriously misunderstand his question, I believe the answer is a
qualified yes. There will still be situations where a run-time check is
necessary. Consider for example the hierarchy (TFoo is at the top)

TFoo --> TBar --> TBaz
      |
      |--> TFrob

TFrobboz (a separate hierarchy not rooted at TFoo)

The compiler can certainly detect that variables typed to one of the
subclasses TBar, TBaz, TFrob are definitely also of class TFoo and that they
are never TFrobboz's.

The run-time checks are required when you have variables of type/class TFoo
and wish to distinguish between TBar, TBaz, and TFrob. In other words, the
dynamic type is different from the static type. For example, calling a
method of TBaz when the static type is TFoo or TBar. The implementation of
(and theory behind) the notion of 'type extension' is discussed in the
paper:

N. Wirth, "Type Extensions", ACM TOPLAS, Vol 10(2), April 1988, 204-214.

I presume there's something similar in the work done by various folks (Ralph
Johnson's name comes to mind) on typed Smalltalk. The terminology may be
different, but I think the concepts are similar.
-- 
Send compilers articles to compilers@iecc.cambridge.ma.us or
{ima | spdcc | world}!iecc!compilers.  Meta-mail to compilers-request.

gateley@rice.edu (John Gateley) (01/16/91)

Is it possible to do static type checking with dynamic scoping?

Well, not really. Consider the following program:

procedure foo (x:int) ...;

procedure bar (x:string) ...;

procedure baz (...) ... x ...;

What type will baz's x have, int or string? One solution that may be
possible is to construct the call graph and make sure that all bindings of x
which reach a given use have the same type. There are some drawbacks to this
solution - it is a "whole program" strategy, separate compilation is not
allowed (without lots of work). It also cannot correctly type check some
programs which are nevertheless legal. For example, the use in baz may be
limited to the x:string binding, but the call graph (constructed at compile
time) may reflect a call from foo which is never taken.

A more restrictive solution is to treat variables as global - assign them
types at the global level. Then all bindings of the variable has to match
that type.

One thing that really messes life up is 1st-class functions. They make the
call graph impossible to construct at compile time.

Are you sure you really want dynamic binding?

John
gateley@rice.edu
-- 
Send compilers articles to compilers@iecc.cambridge.ma.us or
{ima | spdcc | world}!iecc!compilers.  Meta-mail to compilers-request.

brm@Neon.Stanford.EDU (Brian R. Murphy) (01/16/91)

It seems to me that one could consider (dynamically bound) free
variables in a procedure to simply be additional parameters to the
procedure.  Then standard ML-like type inference could be done.

Not being fluent with ML syntax, I give an example in (dynamically
scoped) Lisp:
	(defun f (x)
	    (y x)) ;; y free, bound dynamically
Here f might taken to have type:
	([y: a->b], a) -> b
that is, it takes an argument of type a, a binding of y with type a->b,
and returns a value of type b.

A place where f is used might look like:
	(let ((y sub1))
	    (f 3))
where y has type
	int -> int
and f is applied to ([y:int->int], int) which may be unified with the
above, yielding a result of int as well.

Keeping track of all of the current bindings and determining which
onese were relevant in a particular application would certainly
clutter up the type inference, but it shouldn't make it terribly
more difficult.

					-Brian Murphy
					 brm@cs.stanford.edu
-- 
Send compilers articles to compilers@iecc.cambridge.ma.us or
{ima | spdcc | world}!iecc!compilers.  Meta-mail to compilers-request.

brm@Neon.Stanford.EDU (Brian R. Murphy) (01/18/91)

> Does this work even when side-effects to dynamically-bound variables are
> allowed, e.g.

This should be closely related to how ML would handle side-effects to
variables.  I'm not really sure how this happens (haven't done type
inference for non-functional languages).  

The problems of type inference for Lisp are actually quite a bit more
complex.  You could probably do something like what Alex Aiken and I
did for FL (described pretty abstractly in our POPL paper which will
be presented next week, Type Inference in a Typeless Language, in more
detail in my 1990 MIT MS thesis).  The mechanism we used should be
fairly easily extensible to variable side-effecting, but would suffer
from terrible performance problems without further improvements.

Does anyone know a reference for how ML handles side-effects to variables?  

					-Brian
-- 
Send compilers articles to compilers@iecc.cambridge.ma.us or
{ima | spdcc | world}!iecc!compilers.  Meta-mail to compilers-request.

mac@eleazar.dartmouth.edu (Alex Colvin) (01/21/91)

As an aside - languages such as C++ do static type checking on
dynamically bound (virtual) methods.  In that case the dynamic chain
isn't the call chain, but the derived class chain.  It turns out that
this covers a number of the classic uses of dynamic binding, such as
passing a radix to your print function.

[From mac@eleazar.dartmouth.edu (Alex Colvin)]
-- 
Send compilers articles to compilers@iecc.cambridge.ma.us or
{ima | spdcc | world}!iecc!compilers.  Meta-mail to compilers-request.