[Types-sig] namespaces

Greg Stein gstein@lyra.org
Fri, 21 Jan 2000 06:19:05 -0800 (PST)


On Fri, 21 Jan 2000, scott wrote:
> Stack evaluation looks good, that clears up a lot for me re: runtime
> behavior. but there are problems with both !  (pushes type checking
> errors from compile time to runtime)

'!' can *definitely* invoke a compile-time check:

  x = 5
  y = x!string  # Boom!

The operator also provides information to the type-checker.

> and isinstance:  it's
> grammatically ambiguous as a designator of sections of code blocks
> which may assume disambiguated alternate types.  This becomes quite
> evident if you try to write a checker with a function call that is the
> runtime disambiguating agent.

I agree. I posed to Guido a while back that I do not believe we can use
isinstance() to propertly typecheck the following code:

  if isinstance(x, int):
    return x + 5
  if isinstance(x, str):
    return x + 'hi'

Specifically, because the two parameters are arbitrary expressions, it
will be reasonably complicated to understand the type specified by the
second argument, and to determine that the first argument is an lvalue
(meaning we can record the type on the lvalue). Moreover, it is difficult
to "temporarily" record "int" for "x" within the if: block (up to that
point, we think x is int|str).

Strictly: yes, we could typecheck it (IFF the user followed predefined
patterns and restrictions). Would I want to write the code? Gack. No :-)

I'd rather avoid those restrictions and rely on a clean mechanism.
(described below)


> Are there any other ideas or
> workarounds with these ideas that address these problems?

I am advocating against a new typecase statement.

Specifically, Python does not have a switch statement right now for
reasons "X" and "Y" (exercise for the reader). I think those same reasons
could be applied to a typecase statement. Here is Guido's example, and my
interpretation:

  decl x: int | string | None | [any] | ...

  typecase x:
    int, i:    print "an int: %d" % i
    string, s: print "a string: %s" % `s`
    None:      print "nothing"
    else:      print "don't know"

  if isinstance(x, int):
    print "an int: %d" % (x!int)
  elif isinstance(x, string):
    print "a string: %s" % `x!string`
  elif isinstance(x, None):
    print "nothing"
  else:
    print "don't know"


Of course, that is a *very* literal translation. We only need the (x!int)
form if the type-checker compares formats against input types. The
x!string is unnecessary since `` works on any input type. Using isinstance
to check for None is too heavyweight.

But, let's use a "better" example:

  def munge(x: int|str)->int|str:

    # the typecase form:

    typecase x:
      int, i:
        return i + 5
      # can't use else: here, because we need the "casting" performed by
      # the typecase statement to assign a value to "s"
      str, s:
        return s + 'hi'


    # the Greg form:

    if isinstance(x, int):
      return x!int + 5
    # this could be an else: or omitted (because of the preceding return)
    if isinstance(x, str):
      return x!str + 'hi'


Specifically, I think we should use if/elif/else statements rather than a
typecase. In combination with the '!' operator, we successfully pass the
type-check step without errors.

It is true that isinstance() is a bit more wordy, but I doubt the above
code patterns will be all that common. (can somebody supply some
examples?)

Here is what I find will be *very* common:

  decl checked_module

  import third_party_unchecked_module as tpum

  x = tpum.func()         # by definition, return type is "any"
  func_taking_str(x!str)  # we know it is a string and need to say so


In other words, I think the '!' will be common when dealing with unchecked
modules. I don't think it will be used all that often to narrow types down
from a set of alternatives (which is the purpose of a typecase statement).
Therefore, I'd rather avoid introducing the typecase syntax -- not enough
benefit for the cost of the additional syntax.

Cheers,
-g

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