[Types-sig] examples (was: recursive types, type safety, and flow analysis)

Greg Stein gstein@lyra.org
Wed, 22 Dec 1999 16:50:52 -0800 (PST)


On Wed, 22 Dec 1999, Paul Prescod wrote:
> Greg Stein wrote:
> > I'm talking about figuring out types from the assignments, not from
> > declarations. That's it. Forget declarations and the clutter that they
> > bring to programs.
> 
> Okay, let's try again.
> 
> a.py:
> 
> a=5
> 
> if something():
> 	a = 5
> elif somethingElse():
> 	a = "abc"
> elif somethingElse2():
> 	a = 32L
> elif somethingElse3():
> 	a = ["ab"]
> else:
> 	del a

As John stated: at the end of this code block, "a" is one of Int, String,
Long, List<String>, or Undefined.

There are no errors.

"a" does not form part of a.py's interface as it is not explicitly
mentioned in a "decl member" statement.
[ below, I explore the ramifications of changing this feature/design ]

> b.py:
> 
> import a
> a.a = "jab"

I would say this is perfectly acceptable. Remember: I'm proposing to defer
all assignment enforcement.

No errors.

> c.py:
> 
> import a
> a.a = ("abc",5)

Same as b.py.

> d.py:
> 
> import a, b, c
> 
> j: Int
> j = a.a
> 
> What's the error message? What are the list of valid types that a.a
> could have at this point and how would the type system have inferred
> them?

None of the modules above export an interface. Especially with regard to
module attributes (i.e. module globals). I do believe that a module
exports function signatures as part of its interface; but unless you
include a "decl member" in there, the module does not export defined
attributes.

In my proposal, I would state that ".a" is not part of a's interface, so
the reference simply fails. This is analogous to:

  some_instance.undefined_attribute

In other words, Module "a" and "some_instance" both export an interface.
It is an error to reference something that is NOT part of that interface.

For discussion's sake, because I think you are seeking more detail around
this particular fragment... Let us posit that referencing "a.a" is allowed
(for discussion: let's say we make allowances for module interfaces).

Given that: the expression "a.a" is not type-checked at all. We know that
"a" is a Module, but nothing more. a.a might raise an AttributeError, but
we can't know, and we don't flag that. If it does have a value, we will
treat it as type "Any".

The assignment to "j" succeeds because I don't want local declarations or
assignment enforcement.

==========================================

Now. Let's weaken some of my assumptions/requirements and/or look further
ahead.

1) module globals implicitly form part of an exported interface.

   This would imply that "a.a" has an exported type (the union described
   above). Things like "b.a" would also be exported (with a type of
   Module), but that doesn't enter into this discussion.

   Given this, the type-checker will know that the RHS of "j = a.a" has
   that union type. No error is raised because enforcement does not exist.

2) Enable assignment enforcement (and local declarations)

   d.py issues an error at the assignment.

3) Enable module attribute assignment enforcement (by virtue of an
   exported interface, clients must respect the typedecls specified)

   b.py does not raise an error. String is a valid type for a.a.

   c.py raises an error. A tuple is an invalid type for a.a.

4) Module attribute assignment is outright forbidden.

   b.py and c.py raise errors. These assignments are forbidden.
   
5) Separate track: references to an attribute that is not part of a Module
   interface is noted as an error.

   b.py, c.py, and d.py would raise an error because "a" is not part of
   the Module interface (it was not declared).

   [ per my note above: I do think that these references to "a.a" would
     cause an error because of the interface violation -- a.a is not
     exported by the Module. ]

Items 2, 3, 4 are conditioned upon "a" being part of Module a's interface
(implicitly per #1, or explicit via a declaration).

In summary, the deferred parts of my proposal are:

1) a module global does not form part of its interface unless it is
   explicitly declared with a "decl member" statement.
2) assignment enforcement does not exist
3) module attribute assignments are legal and un-type-checked

Cheers,
-g

-- 
Greg Stein, http://www.lyra.org/