[Python-ideas] Re: Generalized deferred computation in Python

2022-06-24 Thread Chris Angelico
On Sat, 25 Jun 2022 at 11:56, Joao S. O. Bueno  wrote:
>
>
>
> On Fri, Jun 24, 2022 at 10:05 PM Chris Angelico  wrote:
> >
>
> > Hmmm, I think possibly you're misunderstanding the nature of class
> > slots, then. The most important part is that they are looked up on the
> > *class*, not the instance; but there are some other quirks too:
>
>
> Sorry, no. I know how those work.
>
> > >>> class Meta(type):
> > ... def __getattribute__(self, attr):
> > ... print("Fetching %s from the metaclass" % attr)
> > ... return super().__getattribute__(attr)
> > ...
> > >>> class Demo(metaclass=Meta):
> > ... def __getattribute__(self, attr):
> > ... print("Fetching %s from the class" % attr)
> > ... return super().__getattribute__(attr)
> > ...
> > >>> x = Demo()
> > >>> x * 2
> > Traceback (most recent call last):
> >   File "", line 1, in 
> > TypeError: unsupported operand type(s) for *: 'Demo' and 'int'
> >
> > Neither the metaclass nor the class itself had __getattribute__
>
> Yes - if you go back to my first e-mail on the thread, and the example code,
> that is why I am saying all along the proxy have to explicitly define all
> possible dunder methods.

This is part of the problem: "your first email" is now trying to
function as a brand new proposal, yet you're also saying that this is
part of the deferred evaluation proposal that David Mertz put forward.

Maybe this would have been less confusing if you'd simply proposed it
as a stand-alone feature, instead of answering a different post.

> No, not in Python.
> Once you have a proxy class that cover all dundeer methods to operate and 
> return
> the proxied object, whoever will make use of that proxy will have it working 
> in a transparent way.
> In any code that don't try direct memory access to the proxied object data.
> "Lelo" objects from that link can be freely passed around and used -
> at one point, if the object is not dropped, code has to go through one of the 
> dunder methods -
> there is no way Python code can do any calculation or output the proxied 
> object without doing so.
> And that experiment worked fantastically fine in doing so, better than I 
> thought it would,
> and that is the only thng I am trying to say.

So your proxy has to have code for every single dunder method, and any
time a new one is devised, it has to be added? That sounds like a
maintenance nightmare.

> > The original proposal, if I'm not mistaken, was that the "deferred
> > thing" really truly would become the resulting object. That requires
> > compiler support, but it makes everything behave sanely: basic
> > identity checks function as you'd expect, there are no bizarre traps
> > with weak references, C-implemented functions don't have to be
> > rewritten to cope with them, etc, etc, etc.
>
> So, as I 've written from the first message, this would require deep suport in
> the language, which the proxy approach does not.

Yes, that proposal requires proper language support. But things that
require no language support aren't even language proposals, they're
just "hey check out this thing that can be done". Of course there's
always a way to do it in pure Python right now; the question is
really: how limited is the existing version, and how cumbersome is it
to write?

What you're proposing is VERY cumbersome - you have to enumerate
*every single dunder method* and make sure they are perfectly proxied
- and limited in a number of ways.

> > Your proposal is basically just a memoized lambda function with
> > proxying capabilities. The OP in this thread was talking about
> > deferred expressions. And my proposal was about a different way to do
> > argument defaults. All of these are *different* proposals, they are
> > not just implementations of each other. Trying to force one proposal
> > to be another just doesn't work.
>
> I am not trying to force anything. My idea was to put on the table
> a way to achieve most of the effects of the initial proposal with
> less effort. I guess this is "python-ideas" for a reason.

You're posting as a response to a different thread. The obvious
implication is that you believe your proposal to be a variant of this
one. If that's not the case, and you really just want this to stand
alone, start a new thread, and then it'll be obvious.

> And the "inplace object mutation" is a thing that, for me, looks
> specially scary in terms of complexity of the runtime.
> We had recently another lenghty thread - about splitting
> class declaration with a "forward class declaration", that after
> some lengthy discussion was dismissed because it would
> also require this.

It does have a lot of scariness, and frankly, I don't think it's worth
the cost; but it does at least have something more to offer than just
"magic lambda function that calls itself at some point".

> In my reading of the problem at hand, a "purely transparent proxy" is
> a nice approach. What one does not want is to compute the
> 

[Python-ideas] Re: Generalized deferred computation in Python

2022-06-24 Thread Joao S. O. Bueno
On Fri, Jun 24, 2022 at 10:05 PM Chris Angelico  wrote:
>

> Hmmm, I think possibly you're misunderstanding the nature of class
> slots, then. The most important part is that they are looked up on the
> *class*, not the instance; but there are some other quirks too:


Sorry, no. I know how those work.

> >>> class Meta(type):
> ... def __getattribute__(self, attr):
> ... print("Fetching %s from the metaclass" % attr)
> ... return super().__getattribute__(attr)
> ...
> >>> class Demo(metaclass=Meta):
> ... def __getattribute__(self, attr):
> ... print("Fetching %s from the class" % attr)
> ... return super().__getattribute__(attr)
> ...
> >>> x = Demo()
> >>> x * 2
> Traceback (most recent call last):
>   File "", line 1, in 
> TypeError: unsupported operand type(s) for *: 'Demo' and 'int'
>
> Neither the metaclass nor the class itself had __getattribute__

Yes - if you go back to my first e-mail on the thread, and the example code,
that is why I am saying all along the proxy have to explicitly define all
possible dunder methods.

I've repeateadly written that all _other_ methods and attributes access
go through __getattribute__.
> called, because __mul__ goes into the corresponding slot. HOWEVER:
>
> >>> Demo().__mul__
> Fetching __mul__ from the class
> Traceback (most recent call last):
>   File "", line 1, in 
>   File "", line 4, in __getattribute__
> Fetching __dict__ from the class
> Fetching __class__ from the class
> Fetching __dict__ from the metaclass
> Fetching __bases__ from the metaclass
> AttributeError: 'Demo' object has no attribute '__mul__'. Did you
> mean: '__module__'?
>
> If you explicitly ask for the dunder method, it does go through
> __getattribute__.

Please.
I know that. The thing is if I define in a class both
"__add__" and "__getattribte__" I will cover both
"instance + 0" and "instance.__add__(0)"

.(...)
>
> That's a consequence of it being a proxy, though. You're assuming that
> a proxy is the only option. Proxies are never fully transparent, and
> that's a fundamental difficulty with working with them; you can't
> treat them like the underlying object, you have to think of them as
> proxies forever.

No, not in Python.
Once you have a proxy class that cover all dundeer methods to operate and
return
the proxied object, whoever will make use of that proxy will have it
working in a transparent way.
In any code that don't try direct memory access to the proxied object data.
"Lelo" objects from that link can be freely passed around and used -
at one point, if the object is not dropped, code has to go through one of
the dunder methods -
there is no way Python code can do any calculation or output the proxied
object without doing so.
And that experiment worked fantastically fine in doing so, better than I
thought it would,
and that is the only thng I am trying to say.


>
> The original proposal, if I'm not mistaken, was that the "deferred
> thing" really truly would become the resulting object. That requires
> compiler support, but it makes everything behave sanely: basic
> identity checks function as you'd expect, there are no bizarre traps
> with weak references, C-implemented functions don't have to be
> rewritten to cope with them, etc, etc, etc.

So, as I 've written from the first message, this would require deep
suport in
the language, which the proxy approach does not.

>
> > A similar proxy that is used in day to day coding is a super()
instance, and I
> > never saw one needing  `super(cls, instance) is instance` to be true.
>
> That's partly because super() deliberately does NOT return a
> transparent, or even nearly-transparent, proxy. The point of it is to
> have different behaviour from the underlying instance. So, obviously,
> the super object itself has to be a distinct thing.
>
> Usually, a proxy offers some kind of special value that makes it
> distinct from the original object (otherwise why have it?), so it'll
> often have some special attributes that tie in with that (for
> instance, a proxy for objects stored in a database might have an
> "is_unsaved" attribute/method to show whether it's been assigned a
> unique ID yet). This is one of very few places where there's no value
> whatsoever in keeping the proxy around; you just want to go straight
> to the real object with minimal fuss.

and that is acheived when what happens when all the dunder methods
transparently work on the real object: minimal fuss. inst + other work,
str(inst) work, print(inst) work, because it will call str(inst) further
down,.

>
> > > Then you are not talking about the same thing at all. You're talking
> > > about a completely different concept, and you *are* the "you" from my
> > > last paragraphs.
> >
> > I see.
> > I've stepped in because that approach worked _really_ well, and I don't
think
> > it is _all_ that different from the proposal on the thread, and is
instead a
> > middleground not involving "inplace object mutation", 

[Python-ideas] Re: Generalized deferred computation in Python

2022-06-24 Thread Chris Angelico
On Sat, 25 Jun 2022 at 10:37, Joao S. O. Bueno  wrote:
>
>
>
> On Fri, Jun 24, 2022 at 5:38 AM Chris Angelico  wrote:
> >
> > On Fri, 24 Jun 2022 at 16:34, Joao S. O. Bueno  
> > wrote:
> > > On Fri, Jun 24, 2022 at 1:06 AM Chris Angelico  wrote:
> > >> How much benefit would this be? You're proposing a syntactic construct
> > >> for something that isn't used all that often, so it needs to be a
> > >> fairly dramatic improvement in the cases where it _is_ used.
> > >>
> > >
> > > Excuse-me
> > > Who is the "you" you are referring to in the last paragraphs?
> > > (honest question)
> > >
> > > I am not proposing this - the proto-pep is David Mertz' .
> >
> > You, because you're the one who devised the version that I was
> > responding to. His version is a much more in-depth change, although it
> > has other issues.
>
> ok.
> >
> > > I just pointed out that the language, as it is today,can handle
> > > the inner part of the deferred object, as it is.
> >
> > Yes, but with the limitations that I described.
>
> Indeed - I don't want to argue about that, just point out
> that the natural way things work in Python as is,
> some of those limitations do not apply.
>
> > > (if one just adds all possible  dunder methods to your proxy example
> > > above, for example)
> >
> > I still don't understand why you treat dunder methods as special here.
> > Are you, or are you not, relying on __getattribute__? Have you taken
> > tp_* slots into account?
> I had not thought about tp_*slots - I am just considering pure Python
> code: any slot which does not alias to a visible dunder method would
> map to the proxy instead, in a straightforward way for one looking
> only at the Python code. Maybe some of the not mapped slots might cause
> some undesired effects, and should trigger the resolve as well.
>
> . The reason I am treating dunder attributes as special is simply because
> it is what cPython does when resolving any operator with an object - any other
> attribute access, from Python code, goes through __getattribute__, but
> the code path triggered by operators (+, -, ..., not, len, str) does not.

Hmmm, I think possibly you're misunderstanding the nature of class
slots, then. The most important part is that they are looked up on the
*class*, not the instance; but there are some other quirks too:

>>> class Meta(type):
... def __getattribute__(self, attr):
... print("Fetching %s from the metaclass" % attr)
... return super().__getattribute__(attr)
...
>>> class Demo(metaclass=Meta):
... def __getattribute__(self, attr):
... print("Fetching %s from the class" % attr)
... return super().__getattribute__(attr)
...
>>> x = Demo()
>>> x * 2
Traceback (most recent call last):
  File "", line 1, in 
TypeError: unsupported operand type(s) for *: 'Demo' and 'int'

Neither the metaclass nor the class itself had __getattribute__
called, because __mul__ goes into the corresponding slot. HOWEVER:

>>> Demo().__mul__
Fetching __mul__ from the class
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 4, in __getattribute__
Fetching __dict__ from the class
Fetching __class__ from the class
Fetching __dict__ from the metaclass
Fetching __bases__ from the metaclass
AttributeError: 'Demo' object has no attribute '__mul__'. Did you
mean: '__module__'?

If you explicitly ask for the dunder method, it does go through
__getattribute__. In other words, even though methods are able to
customize the behaviour of operators, the behaviour of operators is
not defined in terms of method lookups. (This is particularly obvious
with function objects, which have __call__ methods; obviously the
effect of calling a function cannot be to look up its __call__ method
and call that, as it would lead to infinite recursion.)

> > > Moreover, there could be an attribute namespace to deal/modify the object
> > > so - retrieving the "real" object could be trivial. (the original would
> > > actually be retrieved in _any_ operation with with the object that would
> > > make use of its dunder attributes - think "str", or "myobj + 3", since 
> > > the proxy
> > > dunder would forward the operation to the wrapped object corresponding
> > > method.
> >
> > Okay, here's an exercise for you. Given any function f(), ascertain
> > whether these two calls returned the same object:
> >
> > x = f()
> > y = later f()
> >
> > You do not know what kind of object it is. You just have to write the
> > code that will answer the question of whether the second call to f()
> > returned the exact same object as the first call. Calling str() on the
> > two objects is insufficient, for instance. Calling id(y) is not going
> > to touch any of y's dunder methods - it's just going to return the ID
> > of the proxy, so it'll always show as different.
>
> It won't work, indeed. unless there are reserved attributes that would cause 
> the
> explicit resolve. Even if it is not given, and there is no way for a "is" 
> 

[Python-ideas] Re: Generalized deferred computation in Python

2022-06-24 Thread Joao S. O. Bueno
On Fri, Jun 24, 2022 at 5:38 AM Chris Angelico  wrote:
>
> On Fri, 24 Jun 2022 at 16:34, Joao S. O. Bueno 
wrote:
> > On Fri, Jun 24, 2022 at 1:06 AM Chris Angelico  wrote:
> >> How much benefit would this be? You're proposing a syntactic construct
> >> for something that isn't used all that often, so it needs to be a
> >> fairly dramatic improvement in the cases where it _is_ used.
> >>
> >
> > Excuse-me
> > Who is the "you" you are referring to in the last paragraphs?
> > (honest question)
> >
> > I am not proposing this - the proto-pep is David Mertz' .
>
> You, because you're the one who devised the version that I was
> responding to. His version is a much more in-depth change, although it
> has other issues.

ok.
>
> > I just pointed out that the language, as it is today,can handle
> > the inner part of the deferred object, as it is.
>
> Yes, but with the limitations that I described.

Indeed - I don't want to argue about that, just point out
that the natural way things work in Python as is,
some of those limitations do not apply.

> > (if one just adds all possible  dunder methods to your proxy example
> > above, for example)
>
> I still don't understand why you treat dunder methods as special here.
> Are you, or are you not, relying on __getattribute__? Have you taken
> tp_* slots into account?
I had not thought about tp_*slots - I am just considering pure Python
code: any slot which does not alias to a visible dunder method would
map to the proxy instead, in a straightforward way for one looking
only at the Python code. Maybe some of the not mapped slots might cause
some undesired effects, and should trigger the resolve as well.

. The reason I am treating dunder attributes as special is simply because
it is what cPython does when resolving any operator with an object - any
other
attribute access, from Python code, goes through __getattribute__, but
the code path triggered by operators (+, -, ..., not, len, str) does not.

>
> > Moreover, there could be an attribute namespace to deal/modify the
object
> > so - retrieving the "real" object could be trivial. (the original would
> > actually be retrieved in _any_ operation with with the object that would
> > make use of its dunder attributes - think "str", or "myobj + 3", since
the proxy
> > dunder would forward the operation to the wrapped object corresponding
> > method.
>
> Okay, here's an exercise for you. Given any function f(), ascertain
> whether these two calls returned the same object:
>
> x = f()
> y = later f()
>
> You do not know what kind of object it is. You just have to write the
> code that will answer the question of whether the second call to f()
> returned the exact same object as the first call. Calling str() on the
> two objects is insufficient, for instance. Calling id(y) is not going
> to touch any of y's dunder methods - it's just going to return the ID
> of the proxy, so it'll always show as different.

It won't work, indeed. unless there are reserved attributes that would
cause the
explicit resolve. Even if it is not given, and there is no way for a "is"
comparison,
this derives from the natural usage of the proxy, with no
exceptional behaviors
needed. The proxy is not the underlying object, after all. And not even a
convention such as
a ".__deferred_resolve__" call could solve it: the simpler path I pointed
out does not
involve "in place attribute substitution". But such a method could return
resolve and return the wrapped object, and then:
`(z := resolve(y)) is x`, would work , as well as
id(resolve(y)) == id(x),  but "y"would still be the proxy <- no magic
needed,
and that is the point I wanted to bring.

A similar proxy that is used in day to day coding is a super() instance,
and I
never saw one needing  `super(cls, instance) is instance` to be true.

[...]
> Then you are not talking about the same thing at all. You're talking
> about a completely different concept, and you *are* the "you" from my
> last paragraphs.

I see.
I've stepped in because that approach worked _really_ well, and I don't
think
it is _all_ that different from the proposal on the thread, and is instead
a
middleground not involving "inplace object mutation", that could make
something very
close to that proposal feasible.

Maybe I'd be more happy to see a generic way to implement "super proxys"
like these in a less hacky way, and then those could be used to build the
deferred objects
as in this proposal, than this specific implementation. In the example
project itself, Lelo,  the
proxys are used to calculate the object in a subprocess, rather than just
delaying their
resolve in-thread.

>
> > I just wrote because it is something I made work before - and if there
are indeed
> > uses for it, the language might not even need changes to support it
> > beyond an operator keyword.
> >
>
> Yes, you've done something that is broadly similar to this proposal,
> but like every idea, has its own set of limitations. It's easy to say
> "I did something different 

[Python-ideas] Re: dataclass field argument to allow converting value on init

2022-06-24 Thread Dexter Hill
I don't mind that solution although my concern is whether it would be confusing 
to have `init` have two different purposes depending on the argument. And, if 
`__post_init__` was overrided, which I would say it commonly is, that would 
mean the user would have to manually do the conversion, as well as remembering 
to add an extra argument for the conversion function (assuming I'm 
understanding what you're saying).

If no type was provided to `init` but a conversion function was, it would be a 
case of getting the type from the function signature, right?
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/CAS4EAIEUBYRHRBO54XAZQFC5ABL6HAZ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Adopting better naming conventions (food for thought)

2022-06-24 Thread Paul Moore
That would break huge amounts of existing code. While better names
might have been nice from the start, improving the naming is nowhere
near enough benefit to justify such a disruptive change at this point
in Python's development.

Paul

On Fri, 24 Jun 2022 at 22:47, abed...@gmail.com  wrote:
>
> I was reading some of Kevlin Henney's views on naming conventions, and I 
> realized that, of the 65 classes that make up Python's built-in exceptions, 
> only 8 (by my count) satisfy Henney's pretty basic concept of a good 
> Exception name:
>
> The name should represent whatever the problem is, and should do so directly 
> and specifically. To add Exception to the end is either redundant — so remove 
> it — or an indication of a poor name — so rename it.
>
> Those are:
> SystemExit, KeyboardInterrupt, GeneratorExit, Exception, StopIteration, 
> StopAsyncIteration, Warning, and BaseException (though Henney also 
> discourages the use of "Base" in a base-class's name)
>
> I'm sure there are others throughout the standard library too.
>
> I always caution novice programmers to err on the side of pragmatism over 
> dogmatic adherence to "sacred truths". To that end:
>
> 1) I realize changing built-in exception names would break backwards 
> compatibility and probably isn't worth doing. This post is more intended as 
> food for thought going forward and to bring more attention to Kevlin Henney's 
> ideas.
>
> 2) I think many of the built-in exceptions are actually fine, particularly 
> ones that represent a broad class of more specific exceptions like OSError. I 
> don't think OSError has a specific enough name to be raised on its own 
> (perhaps it should be abstract or otherwise not directly instantiable?), but 
> catching error categories can be pretty helpful even if they don't lend 
> themselves to explicit names.
>
> I would suggest a more ideal naming scheme would be something like the 
> following:
>
> BaseException -> Exception
> # The text for GeneratorExit seems to indicate that in Python, an Error is 
> considered a subclass of an Exception, so this naming seems more appropriate 
> though it contradicts other views on the distinction between Exception and 
> Error.
>
> SystemExit
> KeyboardInterrupt -> UserInterrupt
> #This is supposed to capture a user-initiated exit, whether it came from a 
> keyboard or a magic wand is generally much less relevant
> GeneratorExit
> Exception -> Error
>
> StopIteration
> StopAsyncIteration
> ArithmeticError
>
> FloatingPointError -> Not used, get rid of it?
> OverflowError -> Overflow
> ZeroDivisionError -> ZeroDivision or Undefined
>
> AssertionError -> Contradiction or AssertionViolation
> AttributeError
>
> + AttributeNotFound or AttributeUnavailable
> + AttributeUnassignable
>
> BufferError
>
> 
>
> EOFError -> EndOfFile
> ImportError
>
> ModuleNotFoundError -> ModuleNotFound
>
> LookupError
>
> IndexError -> IndexOutOfBounds
> KeyError -> KeyNotFound
>
> MemoryError -> OutOfMemory
> NameError -> InvalidName (Not needed?)
>
> UnboundLocalError -> UnboundLocal
>
> OSError
>
> BlockingIOError -> BlockingIO
> ChildProcessError -> ChildProcessFailed
> ConnectionError
>
> BrokenPipeError -> BrokenPipe
> ConnectionAbortedError -> ConnectionAborted
> ConnectionRefusedError -> ConnectionRefused
> ConnectionResetError -> ConnectionReset
>
> FileExistsError -> FileAlreadyExists
> FileNotFoundError -> FileNotFound
> InterruptedError -> Interrupted
> IsADirectoryError -> NotAFile
> NotADirectoryError -> NotADirectory
> PermissionError -> PermissionDenied
> ProcessLookupError -> ProcessNotFound
> TimeoutError -> Timeout
>
> ReferenceError -> ReferentCollected?
> RuntimeError
>
> NotImplementedError -> NotImplemented
> RecursionError -> MaxRecursionDepthExceeded or RecursionOverflow
>
> SyntaxError
>
> IndentationError
>
> TabError -> InconsistentIndentation
>
> SystemError -> SystemFailure
> TypeError -> IncompatibleType
> ValueError
>
> UnicodeError
>
> UnicodeDecodeError
> UnicodeEncodeError
> UnicodeTranslateError
>
> Warning
> # Should this be under Error?
>
> DeprecationWarning -> Deprecated
> PendingDeprecationWarning -> Obsolete
> RuntimeWarning
> SyntaxWarning
> UserWarning
> FutureWarning
> ImportWarning
> UnicodeWarning
> BytesWarning
> EncodingWarning
> ResourceWarning
>
> ___
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at 
> https://mail.python.org/archives/list/python-ideas@python.org/message/DRF6EMT3QFPBVTS3S76EEMKHJDCHUHVQ/
> Code of Conduct: http://python.org/psf/codeofconduct/
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 

[Python-ideas] Re: dataclass field argument to allow converting value on init

2022-06-24 Thread Dexter Hill
Didn't think about `attrs` but yes, the converter functionality at a glance 
looks exactly like I'd imagined it would function in dataclasses.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/URDU3TF7BRW724QR2A5TVZALFISD4H6C/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Adopting better naming conventions (food for thought)

2022-06-24 Thread abed...@gmail.com
I was reading some of Kevlin Henney's views on naming conventions 
, and I 
realized that, of the 65 classes that make up Python's built-in exceptions 
, 
only 8 (by my count) satisfy Henney's pretty basic concept of a good 
Exception name:

*The name should represent whatever the problem is, and should do so 
directly and specifically. To add Exception to the end is either redundant 
— so remove it — or an indication of a poor name — so rename it.*

Those are:
SystemExit, KeyboardInterrupt, GeneratorExit, Exception, StopIteration, 
StopAsyncIteration, 
Warning, and BaseException (though Henney also discourages the use of 
"Base" in a base-class's name)

I'm sure there are others throughout the standard library too.

I always caution novice programmers to err on the side of pragmatism over 
dogmatic adherence to "sacred truths". To that end:

1) I realize changing built-in exception names would break backwards 
compatibility and probably isn't worth doing. This post is more intended as 
food for thought going forward and to bring more attention to Kevlin 
Henney's ideas.

2) I think many of the built-in exceptions are actually fine, particularly 
ones that represent a broad class of more specific exceptions like OSError. 
I don't think OSError has a specific enough name to be raised on its own 
(perhaps it should be abstract or otherwise not directly instantiable?), 
but catching error categories can be pretty helpful even if they don't lend 
themselves to explicit names.

I would suggest a more ideal naming scheme would be something like the 
following:

   - BaseException -> Exception
   # The text for GeneratorExit 
    seems 
   to indicate that in Python, an Error is considered a subclass of an 
   Exception, so this naming seems more appropriate though it contradicts other 
   views on the distinction between Exception and Error 
   

   .
  - SystemExit
  - 
*KeyboardInterrupt -> UserInterrupt   *#This is supposed to capture a 
  user-initiated exit, whether it came from a keyboard or a magic wand is 
  generally much less relevant
  - GeneratorExit
  - Exception -> Error
 - *StopIteration*
 - *StopAsyncIteration*
 - *ArithmeticError*
- FloatingPointError -> Not used, get rid of it?
- OverflowError -> Overflow
- ZeroDivisionError -> ZeroDivision or Undefined
- *AssertionError -> Contradiction or AssertionViolation*
 - *AttributeError*
- *+ AttributeNotFound or AttributeUnavailable*
- *+ AttributeUnassignable*
 - *BufferError*
- **
 - *EOFError -> EndOfFile*
 - 
*ImportError *
- ModuleNotFoundError -> ModuleNotFound
- 
*LookupError *
- *IndexError -> IndexOutOfBounds*
- *KeyError -> KeyNotFound*
 - 
*MemoryError -> OutOfMemory *
 - 
*NameError -> InvalidName (Not needed?) *
- UnboundLocalError -> UnboundLocal
 - 
*OSError *
- BlockingIOError -> BlockingIO
- ChildProcessError -> ChildProcessFailed
- ConnectionError
- BrokenPipeError -> BrokenPipe
   - ConnectionAbortedError -> ConnectionAborted
   - ConnectionRefusedError -> ConnectionRefused
   - ConnectionResetError -> ConnectionReset
   - FileExistsError -> FileAlreadyExists
- FileNotFoundError -> FileNotFound
- InterruptedError -> Interrupted
- IsADirectoryError -> NotAFile
- NotADirectoryError -> NotADirectory
- PermissionError -> PermissionDenied
- ProcessLookupError -> ProcessNotFound
- TimeoutError -> Timeout
- 
*ReferenceError -> ReferentCollected? *
 - 
*RuntimeError *
- NotImplementedError -> NotImplemented
- RecursionError -> MaxRecursionDepthExceeded or 
RecursionOverflow
- 
*SyntaxError *
- IndentationError
- TabError -> InconsistentIndentation
   - *SystemError -> SystemFailure*
 - 
*TypeError -> IncompatibleType *
 - 
*ValueError *
- UnicodeError
- UnicodeDecodeError
   - UnicodeEncodeError
   - UnicodeTranslateError
   - *Warning*
 # Should this be under Error?
- DeprecationWarning -> Deprecated
- PendingDeprecationWarning -> Obsolete
 

[Python-ideas] Re: Generalized deferred computation in Python

2022-06-24 Thread David Mertz, Ph.D.
On Fri, Jun 24, 2022 at 10:52 AM Stephen J. Turnbull <
stephenjturnb...@gmail.com> wrote:

> We (not sure how much help I'll be, but I'm in) need to deal with
> Chris A's point that a pure memoizing object doesn't help with the
> mutable defaults problem.  That is with
>
> def foo(cookiejar=defer []):
>
> foo() produces a late bound empty list that will be used again the
> next time foo() is invoked.
>

Yeah... this is a good point, and it is more frustrating to cover the
late-bound argument case.  I welcome edits to the proto-PEP (you can add
yourself as co-author, even if you wind up at -1 on it :-)).

I think I'm more-or-less U+1F922 on "deferred deferred" myself.

濫
-- 
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons.  Intellectual property is
to the 21st century what the slave trade was to the 16th.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/GXVBVCYSTIIA7SVLJYWFDZRBEDRHSUCI/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: dataclass field argument to allow converting value on init

2022-06-24 Thread Steve Jorgensen
Steve Jorgensen wrote:
> Simão Afonso wrote:
> > On 2022-06-23 17:35:59, Steve Jorgensen wrote:
> > What if, instead, the `init` parameter could accept either a boolean
> > (as it does now) or a type? When given a type, that would mean that to
> > created the property and accept the argument but pass the argument ti
> > `__post_init__` rather than using it to initialize the property
> > directly. The type passed to `init` would become the type hint for the
> > argument.
> > What if you wanted to create a boolean type from a function?
> > Then you would pass `type=bool`
Oops. That was another typo. You would pass `init=bool`.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/YAAMMAP4YWLJ5YWZG6DLFLVTBX73MFGR/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: dataclass field argument to allow converting value on init

2022-06-24 Thread Steve Jorgensen
Simão Afonso wrote:
> On 2022-06-23 17:35:59, Steve Jorgensen wrote:
> > What if, instead, the `init` parameter could accept either a boolean
> > (as it does now) or a type? When given a type, that would mean that to
> > created the property and accept the argument but pass the argument ti
> > `__post_init__` rather than using it to initialize the property
> > directly. The type passed to `init` would become the type hint for the
> > argument.
> > What if you wanted to create a boolean type from a function?
Then you would pass `type=bool`
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/C5RAIKFHB3KCXJGGGWYWZAGNQ7OJ3AUS/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Generalized deferred computation in Python

2022-06-24 Thread Chris Angelico
On Sat, 25 Jun 2022 at 00:54, Stephen J. Turnbull
 wrote:
>
> David Mertz, Ph.D. writes:
> > On Fri, Jun 24, 2022 at 3:50 AM Stephen J. Turnbull 
> >  wrote:
>
>  > > I'm suggesting modified semantics where deferreds can be a proxy
>  > > object, whose normal reaction to *any* operation (possibly
>  > > excepting name binding) is
>  > >
>  > > 1.  check for a memoized value,
>  > > if not found evaluate its stored code, and memoize the value
>  > > 2.  perform the action on the memoized value
>  >
>  > I think I like these semantics better than those my draft proposal.  I
>  > haven't had a chance to enhance the proto-PEP more in the last few days
>  > (other work).  But all of these comments are extremely helpful, and I'll
>  > have a better version in a few days.  Hopefully I can address many of the
>  > concerns raised.
>
> We (not sure how much help I'll be, but I'm in) need to deal with
> Chris A's point that a pure memoizing object doesn't help with the
> mutable defaults problem.  That is with
>
> def foo(cookiejar=defer []):
>
> foo() produces a late bound empty list that will be used again the
> next time foo() is invoked.
>
> Now, we could modify the defer syntax in function parameter default
> values to produce a deferred deferred object (or, more likely, a
> deferred object that lacks the memoization functionality).  But I
> suspect Chris will respond with (a polite expression with the
> semantics of) the puke emoji, and I'm not sure I disagree, yet. ;-)

It can't simply lack the memoization functionality, as that would
break the obvious expectation that the list is the same throughout the
function:

def foo(cookiejar=defer []):
cookiejar.append(1) # new list here
cookiejar.append(2) # another new list???

So the only way around it would be to make the defer keyword somehow
magical when used in a function signature, which kinda defeats the
whole point about being able to reuse another mechanic to achieve
this. Also, it would create some other oddity, depending on which way
this is handled:

_default = defer []
def foo(cookiejar=_default):

Does this also get the magic, or doesn't it? Either way, there'd be a
really weird inconsistency here.

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


[Python-ideas] Re: Generalized deferred computation in Python

2022-06-24 Thread Stephen J. Turnbull
David Mertz, Ph.D. writes:
> On Fri, Jun 24, 2022 at 3:50 AM Stephen J. Turnbull 
>  wrote:

 > > I'm suggesting modified semantics where deferreds can be a proxy
 > > object, whose normal reaction to *any* operation (possibly
 > > excepting name binding) is
 > >
 > > 1.  check for a memoized value,
 > > if not found evaluate its stored code, and memoize the value
 > > 2.  perform the action on the memoized value
 > 
 > I think I like these semantics better than those my draft proposal.  I
 > haven't had a chance to enhance the proto-PEP more in the last few days
 > (other work).  But all of these comments are extremely helpful, and I'll
 > have a better version in a few days.  Hopefully I can address many of the
 > concerns raised.

We (not sure how much help I'll be, but I'm in) need to deal with
Chris A's point that a pure memoizing object doesn't help with the
mutable defaults problem.  That is with

def foo(cookiejar=defer []):

foo() produces a late bound empty list that will be used again the
next time foo() is invoked.

Now, we could modify the defer syntax in function parameter default
values to produce a deferred deferred object (or, more likely, a
deferred object that lacks the memoization functionality).  But I
suspect Chris will respond with (a polite expression with the
semantics of) the puke emoji, and I'm not sure I disagree, yet. ;-)

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


[Python-ideas] Re: Generalized deferred computation in Python

2022-06-24 Thread David Mertz, Ph.D.
On Fri, Jun 24, 2022 at 3:50 AM Stephen J. Turnbull <
stephenjturnb...@gmail.com> wrote:

> That's true in David's proposed semantics, where the runtime does that
> check.  I'm suggesting modified semantics where deferreds can be a
> proxy object, whose normal reaction to *any* operation (possibly
> excepting name binding) is
>
> 1.  check for a memoized value,
> if not found evaluate its stored code, and memoize the value
> 2.  perform the action on the memoized value
>

I think I like these semantics better than those my draft proposal.  I
haven't had a chance to enhance the proto-PEP more in the last few days
(other work).  But all of these comments are extremely helpful, and I'll
have a better version in a few days.  Hopefully I can address many of the
concerns raised.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/2JUAXP53V35CEUTNDNV4UY2QRXR364XV/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: dataclass field argument to allow converting value on init

2022-06-24 Thread Simão Afonso
On 2022-06-23 17:35:59, Steve Jorgensen wrote:
> What if, instead, the `init` parameter could accept either a boolean
> (as it does now) or a type? When given a type, that would mean that to
> created the property and accept the argument but pass the argument ti
> `__post_init__` rather than using it to initialize the property
> directly. The type passed to `init` would become the type hint for the
> argument.

What if you wanted to create a boolean type from a function?
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/TR7GFRIYLBWXJEKITMKNIYWKDZC4UH5O/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Generalized deferred computation in Python

2022-06-24 Thread Chris Angelico
On Fri, 24 Jun 2022 at 17:51, Stephen J. Turnbull
 wrote:
> Then the question is, why do we need syntax?  Well, there's the PEP
> 671 rationales for deferring function argument defaults.

Which the OP hasn't actually explained in a way that works yet. A
vanilla argument default value, with any sort of deferred object as
described by anyone in this thread so far, would not achieve the
semantics of a late-bound argument default - usually failing on this
test:

def f(x=[]):
x.append(1)
return x

How do you make this construct a new list every time it is called with
no arguments? "def f(x=later [])" just delays the construction of the
single default list until the first time it's needed, but it won't
create a new one.

>  There is
> also the question of whether name binding should trigger evalution.
> If so,
>
> a = defer b
>
> would (somewhat similar to iter) defer normal b (this could be
> optimized by checking for non-mutables) and "re-defer" a deferred b
> (ie, just bind it to a without evaluation).

Not sure what you mean by "similar to iter", but my understanding of
"a = defer b" (or "a = later b" or whatever the syntax is) is "when a
gets referenced, go figure out what b is", and that's going to have to
go and poke b once a gets poked. There could be an optimization here,
but the vanilla interpretation is that it's a new thunk. The
underlying b won't be evaluated at this point.

> The same consideration
> would apply to "as" and function arguments (possibly with different
> resolutions!  I'm probably missing some name-binding syntax here, but
> it should be clear where this going).

It's not really the name binding that's the consideration - it's the
lookup. Borrowing CPython's bytecode to explain, "a = b" looks like
this: "Load b, then store your latest thing into a". (Both the load
and the store need to know what kind of name to work with - a fast
local, a closure cell (whether from the outer or inner function), a
global, or something harder to optimize ("LOAD_NAME" and "STORE_NAME"
are used in class context).) Name binding should never trigger
evaluation, as that would make it impossible to use deferred objects
at all; but using the name on the RHS would constitute a load, and
based on some versions of the proposal, that is the point at which
evaluation happens.

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


[Python-ideas] Re: Generalized deferred computation in Python

2022-06-24 Thread Chris Angelico
On Fri, 24 Jun 2022 at 16:34, Joao S. O. Bueno  wrote:
> On Fri, Jun 24, 2022 at 1:06 AM Chris Angelico  wrote:
>> How much benefit would this be? You're proposing a syntactic construct
>> for something that isn't used all that often, so it needs to be a
>> fairly dramatic improvement in the cases where it _is_ used.
>>
>
> Excuse-me
> Who is the "you" you are referring to in the last paragraphs?
> (honest question)
>
> I am not proposing this - the proto-pep is David Mertz' .

You, because you're the one who devised the version that I was
responding to. His version is a much more in-depth change, although it
has other issues.

> I just pointed out that the language, as it is today,can handle
> the inner part of the deferred object, as it is.

Yes, but with the limitations that I described.

> (if one just adds all possible  dunder methods to your proxy example
> above, for example)

I still don't understand why you treat dunder methods as special here.
Are you, or are you not, relying on __getattribute__? Have you taken
tp_* slots into account?

> Moreover, there could be an attribute namespace to deal/modify the object
> so - retrieving the "real" object could be trivial. (the original would
> actually be retrieved in _any_ operation with with the object that would
> make use of its dunder attributes - think "str", or "myobj + 3", since the 
> proxy
> dunder would forward the operation to the wrapped object corresponding
> method.

Okay, here's an exercise for you. Given any function f(), ascertain
whether these two calls returned the same object:

x = f()
y = later f()

You do not know what kind of object it is. You just have to write the
code that will answer the question of whether the second call to f()
returned the exact same object as the first call. Calling str() on the
two objects is insufficient, for instance. Calling id(y) is not going
to touch any of y's dunder methods - it's just going to return the ID
of the proxy, so it'll always show as different.

> I am talking about this because I had played around with that "transparent 
> future object"
> in the Lelo project I linked in the other e-mail, and it just works, and
> actually looks like magic, due to it auto-resolving whenever it is
> "consumed".

Right. That auto-resolving requires language support, but it means
that it's not a "transparent future object". It's a real object, just
one that you don't have yet. There *is no object* representing the
pending state.

> But like you, I don't know how useful it would actually be - so I am not the 
> "you"
> from your last paragraphs - I'd not used the "lelo" proxy in production code:
> calling a ".result()" method, or, in these days, having an "await" expression 
> offers
>  something with a lot more control

Then you are not talking about the same thing at all. You're talking
about a completely different concept, and you *are* the "you" from my
last paragraphs.

> I just wrote because it is something I made work before - and if there are 
> indeed
> uses for it, the language might not even need changes to support it
> beyond an operator keyword.
>

Yes, you've done something that is broadly similar to this proposal,
but like every idea, has its own set of limitations. It's easy to say
"I did something different from what you did, and it doesn't require
language support", but your version of the proposal introduces new
problems, which is why I responded to them.

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


[Python-ideas] Re: Generalized deferred computation in Python

2022-06-24 Thread Stephen J. Turnbull
Barry writes:
 > > On 23 Jun 2022, at 08:27, Stephen J. Turnbull  
 > > wrote:

 > Interest idea that ref does not auto evaluate in all cases.
 > I was wondering about what the compile/runtime can do it avoid the costs
 > of checking for an evaluation.

I think the main thing to do is to put the burden on the deferred
object, since it has to be something special in any case.

 > > Now consider a = b + 0.  b.__add__ will be invoked in the usual way.
 > > Only if b is a deferred will evaluation take place.
 > 
 > But the act of checking if b is deferred is a cost I am concerned about.

That's true in David's proposed semantics, where the runtime does that
check.  I'm suggesting modified semantics where deferreds can be a
proxy object, whose normal reaction to *any* operation (possibly
excepting name binding) is

1.  check for a memoized value,
if not found evaluate its stored code, and memoize the value
2.  perform the action on the memoized value

That means that in the statement "a = b + 0", if b is an int,
int.__add__(b, 0) gets called with no burden to code that uses no
deferreds.

Then the question is, why do we need syntax?  Well, there's the PEP
671 rationales for deferring function argument defaults.  There is
also the question of whether name binding should trigger evalution.
If so,

a = defer b

would (somewhat similar to iter) defer normal b (this could be
optimized by checking for non-mutables) and "re-defer" a deferred b
(ie, just bind it to a without evaluation).  The same consideration
would apply to "as" and function arguments (possibly with different
resolutions!  I'm probably missing some name-binding syntax here, but
it should be clear where this going).

 > I would think that it’s not that hard to add the expected check
 > into the python ceval.c
 > And benchmark the impact of the checks. This would not need a full
 > implementation of the deferred mechanism.

+1  Although I'm not going to spend next weekend it. ;-)

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


[Python-ideas] Re: Generalized deferred computation in Python

2022-06-24 Thread Steve Jorgensen
Steve Jorgensen wrote:
> I think I have an idea how to do something like what you're asking with less 
> magic, and I think an example implementation of this could actually be done 
> in pure Python code (though a more performant implementation would need 
> support at the C level).
> What if a deferred object has 1 magic method ( __isdeferred__ ) that is 
> invoked directly rather than causing a thunk, and invocation of any other 
> method does cause a thunk. For the example implementation, a thunk would 
> simply mean that the value is computed and stored within the instance, and 
> method calls on the wrapper are now delegated to that. In the proper 
> implementation, the object would change its identity to become its computed 
> result.

I haven't had any replies to this, but I think it warrants some attention, so 
I'll try to clarify  what I'm suggesting.

Basically, have a deferred object be a wrapper around any kind of callable, and 
give the wrapper a single method __is_deferred__ that does not trigger 
unwrapping. Any other method call or anything else that depends on knowing the 
actual object results in the callable being executed and the wrapper object 
being replaced by that result. From then on, it is no longer deferred.

I like this idea because it is very easy to reason about and fairly flexible. 
Whether the deferred object is a closure or not depends entirely on its 
callable. When it gets unwrapped is easy to understand (basically anything 
other than assignment, passing as an argument, or asking whether it is 
deferred).

What this does NOT help much with is using for argument defaults. Personally, I 
think that's OK. I think that there are good arguments (separately) for dynamic 
argument defaults and deferred objects and that trying to come up with 1 
concept that covers both of those is not necessarily a good idea. It's not a 
good idea if we can't come up with a way to do it that IS easy to reason about, 
anyway.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/OWDM7AUSYECALBQ2JVNQL3H2GH2NFSYV/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Generalized deferred computation in Python

2022-06-24 Thread Joao S. O. Bueno
On Fri, Jun 24, 2022 at 1:06 AM Chris Angelico  wrote:

> On Fri, 24 Jun 2022 at 13:26, Joao S. O. Bueno 
> wrote:
> >
> >
> >
> > On Thu, Jun 23, 2022 at 2:53 AM Chris Angelico  wrote:
> >>
> >> On Thu, 23 Jun 2022 at 11:35, Joao S. O. Bueno 
> wrote:
> >> >
> >> > Martin Di Paola wrote:
> >> > > Three cases: Dask/PySpark, Django's ORM and selectq. All of them
> >> > > implement deferred expressions but all of them "compute" them in
> very
> >> > > specific ways (aka, they plan and execute the computation
> differently).
> >> >
> >> >
> >> > So - I've been hit with the "transparency execution of deferred code"
> dilemma
> >> > before.
> >> >
> >> > What happens is that: Python, at one point will have to "use" an
> object - and that use
> >> > is through calling one of the dunder methods. Up to that time, like,
> just writing the object name
> >> > in a no-operation line, does nothing. (unless the line is in a REPL,
> which will then call the __repr__
> >> > method in the object).
> >>
> >> Why are dunder methods special? Does being passed to some other
> >> function also do nothing? What about a non-dunder attribute?
> >
> >
> > Non-dunder attributes goes through obj.__getattribute__  at which point
> evaluation
> > is triggered anyway.
>
> Hmm, do they actually, or is that only if it's defined? But okay. In
> that case, simply describe it as "accessing any attribute".
>
> >> Especially, does being involved in an 'is' check count as using an
> object?
> >
> >
> > "is" is not "using', and will be always false or true as for any other
> object.
> > Under this approach, the delayed object is a proxy, and remains a proxy,
> > so this would have side-effects in code consuming the object.
> > (extensions expecting strict built-in types might not work with a
> > proxy for an int or str) - but "is" comparison should bring 0 surprises.
>
> At this point, I'm wondering if the proposal's been watered down to
> being nearly useless. You don't get the actual object, it's always a
> proxy, and EVERY attribute lookup on EVERY object has to first check
> to see if it's a special proxy.
>
> >> dflt = fetch_cached_object("default")
> >> mine = later fetch_cached_object(user.keyword)
> >> ...
> >> if mine is dflt: ... # "using" mine? Or not?
> >>
> >> Does it make a difference whether the object has previously been poked
> >> in some other way?
> >
> >
> > In this case, "mine" should be a proxy for the evaluation of the call
> > of "fetch_cached_object" which clearly IS NOT the returned
> > object stored in "dflt".
> >
> > This is so little, or so much, surprising as verifying that "bool([])"
> yields False:
> > it just follows the language inner workings, with not special casing.
>
> If it's defined as a proxy, then yes, that's the case - it will never
> be that object, neither before nor after the undeferral. But that
> means that a "later" expression will never truly become the actual
> object, so you always have to keep that in mind. I foresee a large
> number of style guides decrying the use of identity checks because
> they "won't work" with deferred objects.
>
> > Of course, this if this proposal goes forward - I am just pointing that
> the
> > existing mechanisms in the language can already support it in a way
> > with no modification. If "is" triggering the resolve is desired, or if
> > is desired the delayed object should  be replaced "in place", instead
> > of using a proxy, another approach would be needed - and
> > I'd favor the "already working" proxy approach I presented here.
> >
> > (I won't dare touch the bike-shedding about the syntax on this, though)
> >
>
> Right, but if the existing mechanisms are sufficient, why not just use
> them? We *have* lambda expressions. It wouldn't be THAT hard to define
> a small wrapper - okay, the syntax is a bit clunky, but bear with me:
>
> class later:
> def __init__(self, func):
> self.func = func
> self.__is_real = False
> def __getattribute__(self, attr):
> self.__makereal()
> return getattr(self.__wrapped, attr)
> def __makereal(self):
> if self.__is_real: return
> self.__wrapped =  self.func()
> self.__is_real = True
>
> x = later(lambda: expensive+expression()*to/calc)
>
> And we don't see a lot of this happening. Why? I don't know for sure,
> but I can guess at a few possible reasons:
>
> 1) It's not part of the standard library, so you have to go fetch a
> thing to do it. If that's significant enough, this is solvable by
> adding it to the stdlib, or even a new builtin.
>
> 2) "later(lambda: expr)" is clunky. Very clunky. Your proposal solves
> that, by making "later expr" do that job, but at the price of creating
> some weird edge cases (for instance, you *cannot* parenthesize the
> expression - this is probably the only place where that's possible, as
> even non-expressions can often be parenthesized, eg import and with
> statements).
>
> 3) It's never actually the result of the expression,