[Python-Dev] Re: Proto-PEP part 1: Forward declaration of classes

2022-04-24 Thread Stephen J. Turnbull
Larry Hastings writes:
 > On 4/22/22 19:36, Terry Reedy wrote:

 > > How about a 'regular' class statement with a special marker of some 
 > > sort.  Example: 'body=None'.
 > 
 > It's plausible.  I take it "body=None" would mean the declaration would 
 > not be permitted to have a colon and a class body.  So now we have two 
 > forms of the "class" statement, and which syntax you're using is 
 > controlled by a named parameter argument.
 > 
 > I think this "body=None" argument changing the syntax of the "class" 
 > statement is clumsy.

How about another predefined keyword in class definitions?

class ForwardDeclared(*bases, metaclass=Meta, declaration=True):
pass

AIUI, in your scheme you can't have a body in a forward declaration,
so in this one you could error on a non-pass body, or just ignore it.

I don't see how you can avoid the 'continue class' statement, if you
want the actual argument to be an arbitrary expression that evaluates
to an incomplete class.  Then the symmetry of the 'forward class'
statement is appealing.  If you restrict it to be a name, though, you
could use

class SomeModule.ForwardDeclared(declaration=False):
# body goes here

I think.

What's the use case for arbitrary expressions vs. a (possibly
qualified) name?  A class factory that produces forward declarations?
Do you have a use case in mind?

I dunno, but all this seems really complicated, unless you go the
proxy object route (which is basically what we have now, except that
str is extremely limited as a proxy, you could call it a PINO :-).
Sure, there are risks if the temporary thing produced by forward
class' escapes, but if both the "thing" and the proxy are limited
enough, there will be little incentive to do that.  Consenting adults.
Just add the FAFO warning label.  Add features when they're called for.

A separate question:
There are going to be metaclasses that define __new__ whose instances
cannot be used in forward declarations because the class object can't
be created until the class body is seen, and therefore cannot be split
into __new_forward__ and __new_continue__, I suppose.  Is that true?

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/SQB63XJWE67NVOT4XT6I3RSU4HS73AGL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Proto-PEP part 1: Forward declaration of classes

2022-04-24 Thread Eric V. Smith

On 4/24/2022 5:42 AM, Stephen J. Turnbull wrote:

What's the use case for arbitrary expressions vs. a (possibly
qualified) name?  A class factory that produces forward declarations?
Do you have a use case in mind?


It's:

x.py:

--8<
forward class A()
--8<

x_impl.py

--8<
import X

continue class X.A:
    # class body here
--8<

It needs to be an expression because it's not defining a name, it 
referring to an existing name. You could use "from X import A" here and 
avoid a dotted expression, but it still needs to be an expression 
referring to an existing "forward class". Even if you restrict it to not 
having dots, it's logically an expression, not a name binding.


Eric


___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/VV53MWDTYQCHBCAQGXLZ4SFCKUEHPQ2K/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Proto-PEP part 1: Forward declaration of classes

2022-04-24 Thread Carl Meyer via Python-Dev
Hi Larry,

On Sat, Apr 23, 2022 at 1:53 AM Larry Hastings  wrote:
> But rather than speculate further, perhaps someone who works on one of the 
> static type analysis checkers will join the discussion and render an informed 
> opinion about how easy or hard it would be to support "forward class" and 
> "continue class".

I work on a Python static type checker.

I think a major issue with this proposal is that (in the
separate-modules case) it requires monkey-patching as an import side
effect, which is quite hard for both humans and static analysis tools
to reason effectively about.

Imagine we have a module `foo` that contains `forward class Bar`, a
separate module `foo.impl` that contains `continue class Bar: ...`,
and then a module `baz` that contains `import foo`. What type of
object is `foo.Bar` during the import of `baz`? Will it work for the
module body of `baz` to create a singleton instance `my_bar =
foo.Bar()`?

The answer is that we have no idea. `foo.Bar` might be a
non-instantiable "forward class declaration" (or proxy object, in your
second variation), or it might be a fully-constituted class. Which one
it is depends on accidents of import order anywhere else in the
codebase. If any other module happens to have imported `foo.impl`
before `baz` is imported, then `foo.Bar` will be the full class. If
nothing else has imported `foo.impl`, then it will be a
non-instantiable declaration/proxy. This question of import order
potentially involves any other module in the codebase, and the only
way to reliably answer it is to run the entire program; neither a
static type checker nor a reader of the code can reliably answer it in
the general case. It will be very easy to write a module `baz` that
does `import foo; my_bar = foo.Bar()` and have it semi-accidentally
work initially, then later break mysteriously due to a change in
imports in a seemingly unrelated part of the codebase, which causes
`baz` to now be imported before `foo.impl` is imported, instead of
after.

There is another big problem for static type checkers with this
hypothetical module `baz` that only imports `foo`. The type checker
cannot know the shape of the full class `Bar` unless it sees the right
`continue Bar: ...` statement. When analyzing `baz`, it can't just go
wandering the filesystem aimlessly in hopes of encountering some
module with `continue Bar: ...` in it, and hope that's the right one.
(Even worse considering it might be `continue snodgrass: ...` or
anything else instead.) So this means a type checker must require that
any module that imports `Bar` MUST itself import `foo.impl` so the
type checker has a chance of understanding what `Bar` actually is.

This highlights an important difference between this proposal and
languages with real forward declarations. In, say, C++, a forward
declaration of a function or class contains the full interface of the
function or class, i.e. everything a type checker (or human reader)
would need to know in order to know how it can use the function or
class. In this proposal, that is not true; lots of critical
information about the _interface_ of the class (what methods and
attributes does it have, what are the signatures of its methods?) are
not knowable without also seeing the "implementation." This proposal
does not actually forward declare a class interface; all it declares
is the existence of the class (and its inheritance hierarchy.) That's
not sufficient information for a type checker or a human reader to
make use of the class.

Taken together, this means that every single `import foo` in the
codebase would have to be accompanied by an `import foo.impl` right
next to it. In some cases (if `foo.Bar` is not used in module-level
code and we are working around a cycle) it might be safe for the
`import foo.impl` to be within an `if TYPE_CHECKING:` block; otherwise
it would need to be a real runtime import. But it must always be
there. So every single `import foo` in the codebase must now become
two or three lines rather than one.

There are of course other well-known problems with import-time side
effects. All the imports of `foo.impl` in the codebase would exist
only for their side effect of "completing" Bar, not because anyone
actually uses a name defined in `foo.impl`. Linters would flag these
imports as unused, requiring extra cruft to silence the linter. Even
worse, these imports would tend to appear unused to human readers, who
might remove them and be confused why that breaks the program.

All of these import side-effect problems can be resolved by
dis-allowing module separation and requiring `forward class` and
`continue class` to appear in the same module. But then the proposal
no longer helps with resolving inter-module cycles, only intra-module
ones.

Because of these issues (and others that have been mentioned), I don't
think this proposal is a good solution to forward references. I think
PEP 649, with some tricks that I've mentioned elsewhere to allow
introspecting annotations u

[Python-Dev] Re: Proto-PEP part 1: Forward declaration of classes

2022-04-24 Thread Joao S. O. Bueno
I am not worried about the bikeshed part of which syntax to use -
and more worried with the possible breaking of a lot of stuff, unless
we work with creation of a non-identical "forward object" that is
rebound, as in plain name binding, when the second part
is declared. I've stated that amidst my ramblings,
but Nick Coghlan managed to keep it suscint at
https://mail.python.org/archives/list/python-dev@python.org/message/DMITVTUIQKJW6RYVOPQXHD54VSYE7QHA/

"""
Something worth considering: whether forward references need to be
*transparent* at runtime. If they can just be regular ForwardRef objects
then much of the runtime complexity will go away (at the cost of some
potentially confusing identity check failures between forward references
and the actual class objects).

ForwardRef's constructor could also potentially be enhanced to accept a
"resolve" callable, and a "resolve()" method added to its public API,
although the extra complexity that would bring may not be worth it.

Cheers,
Nick.

"""

For that matter, syntax wise, it could just be:

break class XX()

...

continue class XX:
...

It gains at once no backwards incompatibility, and reuse concepts that
are already somewhat "grouped together".

On Sun, Apr 24, 2022 at 11:25 AM Eric V. Smith  wrote:

> On 4/24/2022 5:42 AM, Stephen J. Turnbull wrote:
> > What's the use case for arbitrary expressions vs. a (possibly
> > qualified) name?  A class factory that produces forward declarations?
> > Do you have a use case in mind?
>
> It's:
>
> x.py:
>
> --8<
> forward class A()
> --8<
>
> x_impl.py
>
> --8<
> import X
>
> continue class X.A:
>  # class body here
> --8<
>
> It needs to be an expression because it's not defining a name, it
> referring to an existing name. You could use "from X import A" here and
> avoid a dotted expression, but it still needs to be an expression
> referring to an existing "forward class". Even if you restrict it to not
> having dots, it's logically an expression, not a name binding.
>
> Eric
>
>
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/VV53MWDTYQCHBCAQGXLZ4SFCKUEHPQ2K/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/WBXIZLNKWTJGAQLTFJOOPFJ7VCD42U6D/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] What is Modules/rotatingtree.c for?

2022-04-24 Thread Patrick Reader
I've just noticed Modules/rotatingtree.{h,c}, which don't seem to be 
used anywhere. Are they just dead code? If so, is there a reason they 
haven't been removed?


___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/46D6DD3OEZEOH4CUPFKOSLVUG6MHV7BU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Proto-PEP part 1: Forward declaration of classes

2022-04-24 Thread Carl Meyer via Python-Dev
On Sun, Apr 24, 2022 at 10:20 AM Joao S. O. Bueno  wrote:
>
> I am not worried about the bikeshed part of which syntax to use -
> and more worried with the possible breaking of a lot of stuff, unless
> we work with creation of a non-identical "forward object" that is
> rebound, as in plain name binding, when the second part
> is declared. I've stated that amidst my ramblings,
> but Nick Coghlan managed to keep it suscint at
> https://mail.python.org/archives/list/python-dev@python.org/message/DMITVTUIQKJW6RYVOPQXHD54VSYE7QHA/

I don't think name rebinding works. That means that if we have
`forward class Bar` in module `foo` and `continue class Bar: ...` in
module `foo.impl`, if module `baz` does `from foo import Bar`, it will
forever have either the forward reference object or the real class,
and which one it has is entirely unpredictable (depends on import
ordering accidents of the rest of the codebase.) If `baz` happens to
be imported before `foo.impl`, the name `Bar` in the `baz` namespace
will never be resolved to the real class, and isn't resolvable to the
real class without some outside intervention.

> """
> Something worth considering: whether forward references need to be
> *transparent* at runtime. If they can just be regular ForwardRef objects
> then much of the runtime complexity will go away (at the cost of some
> potentially confusing identity check failures between forward references
> and the actual class objects).
>
> ForwardRef's constructor could also potentially be enhanced to accept a
> "resolve" callable, and a "resolve()" method added to its public API,
> although the extra complexity that would bring may not be worth it.
> """

I'm not sure how this `resolve()` method is even possible under the
proposed syntax. If `forward class Bar` and `continue class Bar` are
in different modules, then how can `forward class Bar` (which must
create the "forward reference" object) possibly know which module
`continue class Bar: ...` exists in? How can it know how to resolve
itself?

Carl
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/WLZRZIMPRST52UMINB5VB57TOIQVTYQH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: What is Modules/rotatingtree.c for?

2022-04-24 Thread Gregory P. Smith
On Sun, Apr 24, 2022 at 9:24 AM Patrick Reader <_...@pxeger.com> wrote:

> I've just noticed Modules/rotatingtree.{h,c}, which don't seem to be
> used anywhere. Are they just dead code? If so, is there a reason they
> haven't been removed?
>

grep -R rotatingtree ; grep -R _lsprof

rotatingtree is used by the _lsprof module which is the internal
implementation behind cProfile.

-gps


>
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/46D6DD3OEZEOH4CUPFKOSLVUG6MHV7BU/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/W45DZ2RU75HOKELTMRZY7YL3JH7KS7V5/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Proto-PEP part 1: Forward declaration of classes

2022-04-24 Thread Joao S. O. Bueno
I guess Carl's messages put an end to this proposal as it is.

>From "the language side", I can think of nothing short of actually
transforming _in place_ (like it is possible with instances of
ordinary classes when you assign then a new "__class__") the
"forward referenced object" into the complete classes.

This is not "unfeasable", but would be hackish as never before done,
and there are practical problems: the final size of the class object itself
cannot be known before the final committing of the class-body namespace
into the final-namespace (slots, and inheritance of built-in classes with
different layouts, etc...)

Then, it looks like it only would be remotely practical
for a static type checker if the class continuation is on the same
file as its header. (I think I did not even consider they
being in separate files - of course the name-rebinding
would not work in that case)

On the other hand, if it is practical to declare as header the complete
interface of a class, with the intent of putting the actual methods
with code later on, that is already possible, with typing.protocols ;
whoever would take the time to split a class in two due to annotations,
forward referencing, interface declaration separated from implementation,
can just as well declare a protocol, as it exists today,

I am not sure if typing.Protocol works nicely with inheritance, in the sense
that it could inherit from other protocols or concrete classes, and present
everything inherited as part of its interface, if it does not, then _that_
is the
improvement needed so that what this proto-pep would allow could be
done with them.

best regards,

   js
 -><-


On Sun, Apr 24, 2022 at 1:33 PM Carl Meyer  wrote:

> On Sun, Apr 24, 2022 at 10:20 AM Joao S. O. Bueno 
> wrote:
> >
> > I am not worried about the bikeshed part of which syntax to use -
> > and more worried with the possible breaking of a lot of stuff, unless
> > we work with creation of a non-identical "forward object" that is
> > rebound, as in plain name binding, when the second part
> > is declared. I've stated that amidst my ramblings,
> > but Nick Coghlan managed to keep it suscint at
> >
> https://mail.python.org/archives/list/python-dev@python.org/message/DMITVTUIQKJW6RYVOPQXHD54VSYE7QHA/
>
> I don't think name rebinding works. That means that if we have
> `forward class Bar` in module `foo` and `continue class Bar: ...` in
> module `foo.impl`, if module `baz` does `from foo import Bar`, it will
> forever have either the forward reference object or the real class,
> and which one it has is entirely unpredictable (depends on import
> ordering accidents of the rest of the codebase.) If `baz` happens to
> be imported before `foo.impl`, the name `Bar` in the `baz` namespace
> will never be resolved to the real class, and isn't resolvable to the
> real class without some outside intervention.
>
> > """
> > Something worth considering: whether forward references need to be
> > *transparent* at runtime. If they can just be regular ForwardRef objects
> > then much of the runtime complexity will go away (at the cost of some
> > potentially confusing identity check failures between forward references
> > and the actual class objects).
> >
> > ForwardRef's constructor could also potentially be enhanced to accept a
> > "resolve" callable, and a "resolve()" method added to its public API,
> > although the extra complexity that would bring may not be worth it.
> > """
>
> I'm not sure how this `resolve()` method is even possible under the
> proposed syntax. If `forward class Bar` and `continue class Bar` are
> in different modules, then how can `forward class Bar` (which must
> create the "forward reference" object) possibly know which module
> `continue class Bar: ...` exists in? How can it know how to resolve
> itself?
>
> Carl
>
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/US6OOS7OJMEZKQQC456LDRQKC2HRP72P/
Code of Conduct: http://python.org/psf/codeofconduct/