On Saturday, March 21, 2015, Steven D'Aprano <steve@pearwood.info> wrote:
On Fri, Mar 20, 2015 at 09:59:32AM -0700, Guido van Rossum wrote:

> Union types
> -----------
[...]
> As a shorthand for ``Union[T1, None]`` you can write ``Optional[T1]``;

That only saves three characters. Is it worth it?

I think it is worth it because will be a very common case, and the shortcut is more readable.

cheers,

Luciano
 


> An optional type is also automatically assumed when the default value is
> ``None``, for example::
>
>   def handle_employee(e: Employee = None): ...

Should that apply to all default values or just None? E.g. if I have

    def spam(s: str = 23): ...

should that be inferred as Union[str, int] or be flagged as a type
error? I think that we want a type error here, and it's only None that
actually should be treated as special. Perhaps that should be made
explicit in the PEP.


[...]
> For the purposes of type hinting, the type checker assumes ``__debug__``
> is set to ``True``, in other words the ``-O`` command-line option is not
> used while type checking.

I'm afraid I don't understand what you are trying to say here. I would
have expected that __debug__ and -O and the type checker would be
independent of each other.


[...]
> To mark portions of the program that should not be covered by type
> hinting, use the following:
>
> * a ``@no_type_check`` decorator on classes and functions
>
> * a ``# type: ignore`` comment on arbitrary lines
>
> .. FIXME: should we have a module-wide comment as well?

I think so, if for no other reason than it will reduce the fear of some
people that type checks will be mandatory.



> Type Hints on Local and Global Variables
> ========================================
>
> No first-class syntax support for explicitly marking variables as being
> of a specific type is added by this PEP.  To help with type inference in
> complex cases, a comment of the following format may be used::
>
>   x = []   # type: List[Employee]
>
> In the case where type information for a local variable is needed before
> it is declared, an ``Undefined`` placeholder might be used::
>
>   from typing import Undefined
>
>   x = Undefined   # type: List[Employee]
>   y = Undefined(int)

How is that better than just bringing forward the variable declaration?

    x = []   # type: List[Employee]
    y = 0



> Casts
> =====
>
> Occasionally the type checker may need a different kind of hint: the
> programmer may know that an expression is of a more constrained type
> than the type checker infers.  For example::
>
>   from typing import List
>
>   def find_first_str(a: List[object]) -> str:
>       index = next(i for i, x in enumerate(a) if isinstance(x, str))
>       # We only get here if there's at least one string in a
>       return cast(str, a[index])
>
> The type checker infers the type ``object`` for ``a[index]``, but we
> know that (if the code gets to that point) it must be a string.  The
> ``cast(t, x)`` call tells the type checker that we are confident that
> the type of ``x`` is ``t``.

Is the type checker supposed to unconditionally believe the cast, or
only if the cast is more constrained than the infered type (like str and
object, or bool and int)?

E.g. if the type checker infers int, and the cast says list, I'm not
entirely sure I would trust the programmer more than the type checker.

My feeling here is that some type checkers will unconditionally trust
the cast, and some will flag the mismatch, or offer a config option to
swap between the two, and that will be a feature for type checkers to
compete on.


I'm also going to bike-shed the order of arguments. It seems to me that
we want to say:

    cast(x, T)  # pronounced "cast x to T"

rather than Yoda-speak "cast T x to we shall" *wink*. That also matches
the order of isinstance(obj, type) calls and makes it easier to
remember.


> At runtime a cast always returns the
> expression unchanged -- it does not check the type, and it does not
> convert or coerce the value.

I'm a little concerned about cast() being a function. I know that it's a
do-nothing function, but there's still the overhead of the name lookup
and function call. It saddens me that giving a hint to the type checker
has a runtime cost, small as it is.

(I know that *technically* annotations have a runtime cost too, but
they're once-only, at function definition time, not every time you call
the function.)

Your point below that cast() can be used inside expressions is a valid
point, so there has to be a cast() function to support those cases, but
for the example given here where the cast occurs in a return statement,
wouldn't a type comment do?

    return some_expression  # type: T

hints that some_expression is to be treated as type T, regardless of
what was infered.


> Casts differ from type comments (see the previous section).  When
> using a type comment, the type checker should still verify that the
> inferred type is consistent with the stated type.  When using a cast,
> the type checker trusts the programmer.  Also, casts can be used in
> expressions, while type comments only apply to assignments.


> Stub Files
> ==========
[...]
> Stub files may use the ``.py`` extension or alternatively may use the
> ``.pyi`` extension.  The latter makes it possible to maintain stub
> files in the same directory as the corresponding real module.

I don't like anything that could cause confusion between stub files and
actual Python files. If we allow .py extension on stub files, I'm sure
there will be confusing errors where people somehow manage to get the
stub file imported instead of the actual module they want.

Is there any advantage to allowing stub files use a .py extension? If
not, then don't allow it.


--
Steve
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


--
Luciano Ramalho
|  Author of Fluent Python (O'Reilly, 2015)
|     http://shop.oreilly.com/product/0636920032519.do
|  Professor em: http://python.pro.br
|  Twitter: @ramalhoorg