[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Chris Angelico
On Mon, Oct 25, 2021 at 4:24 PM Christopher Barker  wrote:
>
> On Sun, Oct 24, 2021 at 9:58 AM Chris Angelico  wrote:
>>
>> > > def puzzle(*, a=>b+1, b=>a+1):
>> > > return a, b
>
>
>>
>> > >
>> > > Aside: In a functional programming language
>> > > a = b + 1
>> > > b = a + 1
>> > > would be a syntax (or at least compile time) error.
>
>
> but it's a NameError in Python, yes? or maybe an  UnboundLocalError, 
> depending on context.
>
>>
>> > There are two possibilities: either it's a SyntaxError, or it's a
>> > run-time UnboundLocalError if you omit both of them (in which case it
>> > would be perfectly legal and sensible if you specify one of them).
>
>
> This, indeed, would be similar to the behaviour of the current idiom we're 
> trying to replace:
> In [42]: def fun(a=None, b=None):
> ...: a = a if a is not None else b + 1
> ...: b = b if b is not None else a + 1
> ...: print(f'{a=} {b=}')
>
> similar in the sense that whether it works or not depends on  how the 
> function is called.
> In [45]: fun()
> ---
> TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
>
> In [46]: fun(3)
> a=3 b=4
>
>>
>> > I'm currently inclined towards SyntaxError,
>
>
> Except that it's not invalid syntax -- as far as syntax is concerned, you can 
> put any valid expression in there -- it's only "bad" if it happens to use a 
> name that is also being late bound. Is there any other place in Python where 
> a syntax error depends on what names are used (other than keyworks, of 
> course)?
>

In the first draft of the PEP, I left it underspecified, and was
mentally assuming that there'd be an UnboundLocalError. Making it a
SyntaxError isn't too difficult, since the compiler knows about all
arguments as it's building that bytecode. It's like the checks to make
sure you don't try to declare one of your parameters as 'global'.

There are several reasons that I'm preferring SyntaxError here.

1) No use-case springs to mind where you would want arguments to
depend on each other.
2) If, even years in the future, a use-case is found, it's much easier
to make the language more permissive than less.
3) Precisely matching the semantics of "if x is None: x = "
would allow right-hand references to early-bound defaults but not
other late-bound defaults
4) OTOH, stating that arguments are processed left-to-right implies
that *everything* about each arg is processed in that order
5) If the wrong-direction reference is a bug, it's much more helpful
to get an early SyntaxError than to get UnboundLocalError later and
more rarely.

(BTW: I'm seeing only two options here - SyntaxError at compilation
time or UnboundLocalError at call time. There's no reason to have an
error at function definition time. I could be wrong though.)

> I like how it closely mirrors the current idiom, and I don't think saying 
> that it's evaluated left to right is all that complex.
>
> But no, I can't think of a use case :-)

Yeah, it seems perfectly reasonable, but it becomes messy. Consider:

def fun(a=1, b=2):
print(a, b)

If you change one or both of those to late-bound, it doesn't change
anything. Great! Now:

def fun1(a=>b + 1, b=2):
print(a, b)
def fun2(a=>b + 1, b=>2):
print(a, b)

Having b late-bound doesn't change b in any way, but it could make a
bizarre difference to a's legality, depending on whether "left to
right" means only late-bound defaults, or all argument processing.

We've recently had a bit of a thread on python-list about the
restrictions on assignment expressions, and tying in with that, the
recent relaxing of restrictions on decorators. Both examples give me
confidence that restricting "wrong-direction" references is correct,
at least for now; if it turns out to be wrong, it can be changed.

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/QFHXBSQRUBSXYNWL56QLFQX7Q6WTPRS4/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: def variable = value

2021-10-24 Thread Stephen J. Turnbull
Serhiy Storchaka writes:

 > They have. Both function and type classes have constructors

Ah, right.  "First-class values", of course they do.

Thanks!

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/D7ESLIWVWZ6DJ6PUL7MHHSYFL7UASLOQ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Christopher Barker
On Sun, Oct 24, 2021 at 9:58 AM Chris Angelico  wrote:

> > > def puzzle(*, a=>b+1, b=>a+1):
> > > return a, b



> > >
> > > Aside: In a functional programming language
> > > a = b + 1
> > > b = a + 1
> > > would be a syntax (or at least compile time) error.
>

but it's a NameError in Python, yes? or maybe an  UnboundLocalError,
depending on context.


> > There are two possibilities: either it's a SyntaxError, or it's a
> > run-time UnboundLocalError if you omit both of them (in which case it
> > would be perfectly legal and sensible if you specify one of them).
>

This, indeed, would be similar to the behaviour of the current idiom we're
trying to replace:
In [42]: def fun(a=None, b=None):
...: a = a if a is not None else b + 1
...: b = b if b is not None else a + 1
...: print(f'{a=} {b=}')

similar in the sense that whether it works or not depends on  how the
function is called.
In [45]: fun()
---
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'

In [46]: fun(3)
a=3 b=4


> > I'm currently inclined towards SyntaxError,


Except that it's not invalid syntax -- as far as syntax is concerned, you
can put any valid expression in there -- it's only "bad" if it happens to
use a name that is also being late bound. Is there any other place in
Python where a syntax error depends on what names are used (other than
keyworks, of course)?

I'll leave it to folks that understand the implementation a lot better than
I, but how hard would it be to make that trigger a SyntaxError?

So I vote for UnboundLocalError


> since permitting it would
> > open up some hard-to-track-down bugs, but am open to suggestions about
> > how it would be of value to permit this.
>

Even if not, maybe it should raise UnboundLocalError, rather than
SyntaxError

I like how it closely mirrors the current idiom, and I don't think saying
that it's evaluated left to right is all that complex.

But no, I can't think of a use case :-)

-CHB
___
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/MXELTZXNBDFUIBOBF3AWAWXED34MG6IS/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Chris Angelico
On Mon, Oct 25, 2021 at 3:12 PM Sebastian Berg
 wrote:
>
> On Mon, 2021-10-25 at 03:47 +1100, Chris Angelico wrote:
> > On Mon, Oct 25, 2021 at 3:43 AM Jonathan Fine 
> > wrote:
> > >
> > > Hi
> > >
> > > Please forgive me if it's not already been considered. Is the
> > > following valid syntax, and if so what's the semantics? Here it is:
> > >
> > > def puzzle(*, a=>b+1, b=>a+1):
> > > return a, b
> > >
> > > Aside: In a functional programming language
> > > a = b + 1
> > > b = a + 1
> > > would be a syntax (or at least compile time) error.
> > >
> >
>
> I was about to ask about this.  But also, how does that go together
> with non-required arguments?
>
> def function(arr=>np.asarray(arr)):
>pass
>
> Would seem like something we may be inclined to write instead of:
>
> def function(arr):
> arr = np.asarray(arr)
>
> (if that is legal syntax).  In that case `arr` is a required parameter.
> Which then means that you cannot do it for optional parameters?:

This is all about argument defaults, not transforming values that were
passed in. So if you pass a value, you always get exactly that value.

> def function(arr1=>np.asarray(arr), arr2=>something):
> arr2 = np.asarray(arr2)  # in case arr2 was passed in
>
> Which is fair, but feels like a slightly weird difference in usage
> between required and optional arguments?
>
> > There are two possibilities: either it's a SyntaxError, or it's a
> > run-time UnboundLocalError if you omit both of them (in which case it
> > would be perfectly legal and sensible if you specify one of them).
> >
> > I'm currently inclined towards SyntaxError, since permitting it would
> > open up some hard-to-track-down bugs, but am open to suggestions
> > about
> > how it would be of value to permit this.
>
> Not sure that I am scared of this if it gives a clear exception:
>
> Parameter `a` was not passed, but it can only be omitted when
> parameter `b` is passed.
>
> Not as clear (or complete) as a custom message, but not terrible?
>

A tad complicated and would require some hairy analysis. Also, I don't
really want to encourage argument defaults that depend on each other
:)

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/VVPNAWCKAGBROZSBGQUWDFGZGYMET2NW/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Christopher Barker
+1 to this idea -- thanks Chris A!

On Sat, Oct 23, 2021 at 2:01 PM Bruce Leban  wrote:

> Here's one way you could imagine writing this today:
>>
>
> def bisect(a, x, lo=0, hi=lambda: len(a)):
> hi = hi() if callable(hi) else hi
> ...
>
> which is clumsy and more importantly doesn't work because the binding of
> the lambda occurs in the function definition context which doesn't have
> access to the other parameters.
>

However, it will work if there happens to be an 'a' defined in the scope
where the function is created.

So that means that it could be VERY confusing if the syntax for an
anonymous function is the same (or very similar to) the syntax for delayed
evaluation of parameter defaults.

I think Steven may have posted an example of what it would look like.

I"ll also add that looking again, and "arrow" like symbol really is very
odd in this context, as others have pointed out, it's pointing in the
wrong direction. Not that I have a better idea.

-CHB


-- 
Christopher Barker, PhD (Chris)

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
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/X2P7JKX7RFISVYW74RJALWMIASCFRW5R/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Jonathan Fine
Hi Chris

You wrote:

In fact, on subsequent consideration, I'm inclining more strongly
> towards SyntaxError, due to the difficulty of explaining the actual
> semantics. Changing the PEP accordingly.


Your PEP, so your choice. I now think that if implemented, your PEP adds to
the Python compiler (and also runtime?) tools for detecting and
well-ordering Directed Acyclic Graphs (DAG).

Here's another problem. Suppose
  def puzzle (*, a=>..., z>=...)
gives rise to a directed acyclic graph, and all the initialisation
functions consume and use a value from a counter. The semantics of puzzle
will now depend on the linearization you choose for the DAG.

(This consumption and use of the value from a counter could be internal to
the initialisation function.)

-- 
Jonathan
___
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/JTEA6K6LSDABWKPMGNZSADDENI33VZQC/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Ben Rudiak-Gould
On Sat, Oct 23, 2021 at 5:16 PM Chris Angelico  wrote:

> # Very common: Use None and replace it in the function
> def bisect_right(a, x, lo=0, hi=None, *, key=None):
> if hi is None:
> hi = len(a)
>

Note that if this is changed to

def bisect_right(a, x, lo=0, hi[whatever]len(a), *, key=None):

then you'll lose the ability to pass hi=None to mean the end of the array.
For this argument of bisect_right, None actually makes sense since it's
used for that purpose in slices, and it would probably be a
backward-compatibility problem to drop support for it also. So you will
still have to write

def bisect_right(a, x, lo=0, hi[whatever]len(a), *, key=None):
if hi is None:
hi = len(a)

Self-referential expressions will result in UnboundLocalError::
>
> def spam(eggs=>eggs): # Nope
>

That seems like not a rule of its own, but a special case of this rule:
deferred arguments that haven't been assigned to yet are unbound (and not,
say, set to some implementation-specific value analogous to
_USE_GLOBAL_DEFAULT).


> def bisect(a, hi=>len(a)):
>

That looks like an anonymous function that takes a single parameter named
hi, ignores it, and returns the length of a free variable named a. It may
even mean that in Python someday in expression contexts. But it's
definitely not what it means here.

hi<=len(a) would make a bit more sense.


> def bisect(a, hi=:len(a)):
>

This one annoys me the least, though I can't say why.

def bisect(a, hi?=len(a)):
>

? seems reasonable for omitted/defaulted arguments, but that's not what
this PEP is about. I can't see why call-time evaluation would have a ? and
def-time evaluation wouldn't.

def bisect(a, hi!=len(a)):
>

Same basic problem as => (and <=). Is hi equal to len(a), or not?

def bisect(a, hi=`len(a)`):
>

It looks like the backticks are part of the expression rather than the
function-parameter syntax, but they aren't, and never could be - even if
there was a deferred-evaluation syntax at the expression level, it couldn't
be used here, because the lexical environment would be wrong.


> Since default arguments behave largely the same whether they're early or
> late
> bound,


They seem very different to me. They're evaluated in a different lexical
scope, and many use cases for this extension depend on the changed scoping.
___
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/22DEQDF35SOBW6OC2Z2GGBVAQKIKHMPM/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Erik Demaine

On Sun, 24 Oct 2021, Erik Demaine wrote:

I think the semantics are easy to specify: the argument defaults get 
evaluated for unspecified order, in left to right order as specified in the 
def.  Those may trigger exceptions as usual.


Sorry, that should be:

I think the semantics are easy to specify: the argument defaults get evaluated 
for unspecified ARGUMENT(s), in left to right order as specified in the def. 
Those may trigger exceptions as usual.


___
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/SNAYBJR52DHO3U76RLXZEC7HQFJLKVEX/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Chris Angelico
On Mon, Oct 25, 2021 at 4:29 AM Erik Demaine  wrote:
>
> On Sun, 24 Oct 2021, Erik Demaine wrote:
>
> > I think the semantics are easy to specify: the argument defaults get
> > evaluated for unspecified order, in left to right order as specified in the
> > def.  Those may trigger exceptions as usual.
>
> Sorry, that should be:
>
> I think the semantics are easy to specify: the argument defaults get evaluated
> for unspecified ARGUMENT(s), in left to right order as specified in the def.
> Those may trigger exceptions as usual.
>

Ah, but is it ALL argument defaults, or only those that are
late-evaluated? Either way, it's going to be inconsistent with itself
and harder to explain. That's what led me to change my mind.

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/LM5FMONOQC2ABGMJXEKNN3XBSJVM4LMO/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Erik Demaine

On Mon, 25 Oct 2021, Chris Angelico wrote:


On Mon, Oct 25, 2021 at 3:47 AM Chris Angelico  wrote:


On Mon, Oct 25, 2021 at 3:43 AM Jonathan Fine  wrote:


Please forgive me if it's not already been considered. Is the following valid 
syntax, and if so what's the semantics? Here it is:

def puzzle(*, a=>b+1, b=>a+1):
return a, b


There are two possibilities: either it's a SyntaxError, or it's a
run-time UnboundLocalError if you omit both of them (in which case it
would be perfectly legal and sensible if you specify one of them).

I'm currently inclined towards SyntaxError, since permitting it would
open up some hard-to-track-down bugs, but am open to suggestions about
how it would be of value to permit this.


In fact, on subsequent consideration, I'm inclining more strongly
towards SyntaxError, due to the difficulty of explaining the actual
semantics. Changing the PEP accordingly.


I think the semantics are easy to specify: the argument defaults get evaluated 
for unspecified order, in left to right order as specified in the def.  Those 
may trigger exceptions as usual.


Erik
___
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/HYXNABI2ACLVCLQH5TNRDX6WWSHNOING/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Rob Cliffe via Python-ideas



On 24/10/2021 03:48, Steven D'Aprano wrote:

On Sun, Oct 24, 2021 at 01:16:02PM +1100, Chris Angelico wrote:


And is it really a problem if we delay the late-binding to the point
where the value is actually needed? Here's a toy example:

 # Using only early binding.
 def function(spam, eggs=None, cheese=None):
 if eggs is None:
 eggs = cheap_default()
 # do stuff using eggs
 ...
 if condition:
 return result
 if cheese is None:
 cheese = expensive_default()
 # do stuff using cheese
 ...
 return result



-1.  Too confusing.  Consider

    def function(a, ct=>len(a)):
        if random.randint(0,1):
            a.append(42)
        for i in range(ct):
            # presumably ct may or may not be 1 more than the original 
length of a


Best wishes
Rob Cliffe
___
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/JP6RRLHJ4FAMNYSW7CMLOEXT2GLBBLLE/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Sebastian Berg
On Mon, 2021-10-25 at 03:47 +1100, Chris Angelico wrote:
> On Mon, Oct 25, 2021 at 3:43 AM Jonathan Fine 
> wrote:
> > 
> > Hi
> > 
> > Please forgive me if it's not already been considered. Is the
> > following valid syntax, and if so what's the semantics? Here it is:
> > 
> >     def puzzle(*, a=>b+1, b=>a+1):
> >     return a, b
> > 
> > Aside: In a functional programming language
> >     a = b + 1
> >     b = a + 1
> > would be a syntax (or at least compile time) error.
> > 
> 

I was about to ask about this.  But also, how does that go together
with non-required arguments?

def function(arr=>np.asarray(arr)):
   pass

Would seem like something we may be inclined to write instead of:

def function(arr):
arr = np.asarray(arr)

(if that is legal syntax).  In that case `arr` is a required parameter.
Which then means that you cannot do it for optional parameters?:

def function(arr1=>np.asarray(arr), arr2=>something):
arr2 = np.asarray(arr2)  # in case arr2 was passed in

Which is fair, but feels like a slightly weird difference in usage
between required and optional arguments?

> There are two possibilities: either it's a SyntaxError, or it's a
> run-time UnboundLocalError if you omit both of them (in which case it
> would be perfectly legal and sensible if you specify one of them).
> 
> I'm currently inclined towards SyntaxError, since permitting it would
> open up some hard-to-track-down bugs, but am open to suggestions
> about
> how it would be of value to permit this.

Not sure that I am scared of this if it gives a clear exception:

Parameter `a` was not passed, but it can only be omitted when
parameter `b` is passed.

Not as clear (or complete) as a custom message, but not terrible?

Cheers,

Sebastian


> 
> 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/YVE5PMBV5A7PLX242TMMQH2LW4YL2DXK/
> Code of Conduct: http://python.org/psf/codeofconduct/
> 



signature.asc
Description: This is a digitally signed message part
___
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/6S3AZEL3QIRJGM7CRRXBQYSIJB3KOJJT/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Guido van Rossum
More about thunks. I've resisted the temptation to look at the Wikipedia
page -- this is from memory.

On Sat, Oct 23, 2021 at 11:39 PM Steven D'Aprano 
wrote:

> >   I would prefer to see this situation handled as part of a
> >   larger-scale
> > change of adding some kind of "inline lambda" which executes directly in
> > the calling scope.
>
> That would be what I called a "thunk" in two posts now, stealing the
> term from Algol.
>
> It would be nice if one of the core devs who understand the deep
> internals of the interpreter could comment on whether that sort of
> delayed evaluation of an expression is even plausible for Python.
>

IIRC, a thunk in Algol was more or less defined as "substitute the argument
in each use". There was no expression in the function definition, just an
argument. Translating to Python, we'd have something like this (all
arguments were thunks by default):

def foo(arg):
print(arg)
arg = arg + 1

x = 42
foo(x)
print(x)

This would print 42 and 43. Writing foo(42) would produce an error. But if
you had another function

def bar(arg)
print(arg)

it would be okay to write bar(42).

A key property (IIRC) was that the thunk would be evaluated each time it
was used. This led to "Jensen's device"  where you could write

def foo(a, b, n):
total = 0
for a in range(1, n+1):  # IIRC Algol spelled this 'for a := 1 to n'
total += b
return total

and you'd call it like this:

foo(x, x**2, 10)

which would compute the sum of the squares of i for i i range(10).

It went out of style because it was complex to implement and expensive to
execute -- for example, the 'n' argument would be a thunk too.

You can't easily introduce this in Python because Python is built on not
knowing the signature of foo when the code for the call foo(x, x**2, 10) is
compiled. So it wouldn't be sufficient to mark 'a' and 'b' as thunks in the
'def foo(a, b, n)' line. You'd also have to mark the call site.

Suppose we introduce a \ to indicate thunks in both places. (This is the
worst character but enough to explain the mechanism.)

You'd write

def foo(\a, \b, n):
total = 0
for a in range(1, n+1):
total += b
return total

and you'd call it like

x = None  # dummy
foo(\x, \x**2, 10)


Now the compiler has enough information to compile code for the thunks.
Since thunks can be used as l-values as well as r-values, there would be
two hidden functions, one to get the value, another to set it. The call
would pass an object containing those two functions and the code in the
callee would translate each use of a thunk argument into a call to either
the getter or the setter. Above, the getter functions for x and x**2 are
simple:

get_a = lambda: x
get_b = lambda: x**2

(Defined in the caller's scope.)

The setter function for the first argument would be a bit more complex:

def set_a(val):
nonlocal x
x = val

The second argument's setter function is missing, since 'x+42' is not an
l-value. (We'd get a runtime error if foo() assigned to b.)

If we wanted thunks without assignment and without Jensen's device, we
would only need a getter function. Then \x in the caller would just pass
lambda: x, and an argument marked with \a in a function definition would
cause code to be generated that calls it each time it is used.

Getting rid of the need to mark all thunk arguments in the caller would
require the compiler to have knowledge of which function is being called.
That would require an amount of static analysis beyond what even mypy and
friends can do, so I don't think we should try to pursue that.

The key property of a thunk, IMO, is that it is evaluated in the caller's
scope. It's no different than a function defined in the caller. I don't
think it would be a good substitute for late-binding default arguments.
(You could make something up that uses dynamic scoping, but that's a whole
different can of worms.)

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

___
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/WLRGA3GYYGYY3TDEOEKXR52OEJRALAR2/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Erik Demaine

On Sun, 24 Oct 2021, Chris Angelico wrote:


Is anyone interested in coauthoring this with me? Anyone who has
strong interest in seeing this happen - whether you've been around the
Python lists for years, or you're new and interested in getting
involved for the first time, or anywhere in between!


I have a strong interest in seeing this happen, and would be happy to help how 
I can.  Teaching (and using) the behavior of Python argument initializers is 
definitely a thorn in my side. :-)  I'd love to be able to easily initalize an 
empty list/set/dict.


For what it's worth, here are my thoughts on some of the syntaxes proposed so 
far:


* I don't like `def f(arg => default)` exactly because it looks like a lambda, 
and so I imagine arg is an argument to that lambda, but the intended meaning 
has nothing to do with that.  I understand lambdas give delegation, but in my 
mind that should look more like `def f(arg = => default)` or `def f(arg = () 
=> default)` -- except these will have a different meaning (arg's default is a 
function, and they would be evaluated in parent scope not the function's 
scope) once `=>` is short-hand for lambda.


* I find `def f(arg := default)` reasonable.  I was actually thinking about 
this very issue before the thread started, and this was the syntax that came 
to mind.  The main plus for this is that it uses an existing operator (so 
fewer to learn) and it is "another kind of assignment".  The main minus is 
that it doesn't really have much to do with the walrus operator; we're not 
using the assigned value inline like `arg := default` would mean outside 
`def`.  Then again, `def f(arg = default)` is quite different from `arg = 
default` outside `def`.


* I find `def f(arg ?= default)` (or `def f(arg ??= default)`) reasonable, 
exactly because it is similar to None-aware operators (PEP 0505), which is 
currently/recently under discussion in python-dev).  The main complaint about 
PEP 0505 in those discussions is that it's very None-specific, which feels 
biased.  But the meaning of "omitted value" is extremely clear in a def.  If 
both this were added and PEP 0505 were accepted, `def f(arg ?= default)` would 
be roughly equivalent to:


```
def f(arg = None):
arg ??= default
```

except `def f(arg ?= default)` wouldn't trigger default because in the case 
of `f(None)`, whereas the above code would.  I find this an acceptable 
difference.  (FWIW, I'm also in favor of 0505.)


* I also find `def f(@arg = default)` reasonable, though it feels a little 
inconsistent with decorators.  I expect a decorator expression after @, not 
an argument, more like `def f(@later arg = default)`.


* I'm not very familiar with thunks, but they seem a bit too magical for my 
liking.  Evaluating argument defaults only sometimes (when they get read in 
the body) feels a bit unpredictable.


Erik
--
Erik Demaine  |  edema...@mit.edu  |  http://erikdemaine.org/
___
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/DBDNNYYOVVZ5MITYXC5Q3SC5U2P3ASUS/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Chris Angelico
On Mon, Oct 25, 2021 at 3:47 AM Chris Angelico  wrote:
>
> On Mon, Oct 25, 2021 at 3:43 AM Jonathan Fine  wrote:
> >
> > Hi
> >
> > Please forgive me if it's not already been considered. Is the following 
> > valid syntax, and if so what's the semantics? Here it is:
> >
> > def puzzle(*, a=>b+1, b=>a+1):
> > return a, b
> >
> > Aside: In a functional programming language
> > a = b + 1
> > b = a + 1
> > would be a syntax (or at least compile time) error.
> >
>
> There are two possibilities: either it's a SyntaxError, or it's a
> run-time UnboundLocalError if you omit both of them (in which case it
> would be perfectly legal and sensible if you specify one of them).
>
> I'm currently inclined towards SyntaxError, since permitting it would
> open up some hard-to-track-down bugs, but am open to suggestions about
> how it would be of value to permit this.

In fact, on subsequent consideration, I'm inclining more strongly
towards SyntaxError, due to the difficulty of explaining the actual
semantics. Changing the PEP accordingly.

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/CBXTU5P3I6FTJJI4DB66QOI4OXAU6TNC/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Chris Angelico
On Mon, Oct 25, 2021 at 3:43 AM Jonathan Fine  wrote:
>
> Hi
>
> Please forgive me if it's not already been considered. Is the following valid 
> syntax, and if so what's the semantics? Here it is:
>
> def puzzle(*, a=>b+1, b=>a+1):
> return a, b
>
> Aside: In a functional programming language
> a = b + 1
> b = a + 1
> would be a syntax (or at least compile time) error.
>

There are two possibilities: either it's a SyntaxError, or it's a
run-time UnboundLocalError if you omit both of them (in which case it
would be perfectly legal and sensible if you specify one of them).

I'm currently inclined towards SyntaxError, since permitting it would
open up some hard-to-track-down bugs, but am open to suggestions about
how it would be of value to permit this.

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/YVE5PMBV5A7PLX242TMMQH2LW4YL2DXK/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Jonathan Fine
Hi

Please forgive me if it's not already been considered. Is the following
valid syntax, and if so what's the semantics? Here it is:

def puzzle(*, a=>b+1, b=>a+1):
return a, b

Aside: In a functional programming language
a = b + 1
b = a + 1
would be a syntax (or at least compile time) error.

-- 
Jonathan
___
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/3WHUCMGLKATS3NF7F2LAXIWQUUZ732CK/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread David Mertz, Ph.D.
Yes! Exactly that.

I believe (and believed in some discussions here since maybe 4-5 years ago)
that having something close to the dask.delayed() function baked into the
language works be a good think.

And as a narrow point, it could address the narrower late-bound function
argument matter as one narrow use.

On Sun, Oct 24, 2021, 9:59 AM Steven D'Aprano  wrote:

> On Sun, Oct 24, 2021 at 09:39:27AM -0400, David Mertz, Ph.D. wrote:
>
> > This has been a topic of other threads over the years, and something I've
> > wanted at least since I first worked with Dask's 'delayed()' function.
>
> You mean this?
>
> https://docs.dask.org/en/latest/delayed.html
>
>
>
> --
> 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/ORMQESE5VKVASQPJYYKZT4VT5E6RYEFC/
> 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 
https://mail.python.org/archives/list/python-ideas@python.org/message/CKLX5KHE6ABCK6ZTN6PEZ4CYHIYHLO5B/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Deferred evaluation (was: PEP 671: Syntax for late-bound function argument defaults)

2021-10-24 Thread David Mertz, Ph.D.
On Sun, Oct 24, 2021, 10:11 AM Chris Angelico

> Not sure I understand. Your example was something like:
>
> def fn2(thing):
> a, b = 13, 21
> x = 5
> print("Thing is:", thing)
>
> def f(x=defer: a + b):
> a, b = 3, 5
> fn2(defer: x)
> return x
>
> So inside f(), "defer: a + b" will look in f's scope and use the
> variables a and b from there, but passing a "defer: x" to fn2 will use x
> from f's scope, and then a and b from fn2's?
>

Yes, basically as you describe. A "deferred object" is basically just a
string that knows to wrap itself in eval() when accessed (maybe Steven's
"thunk" is a better term... But definitely something first-class, unlike in
Algol).

So within fn2() the parameter 'thing' is bound to an object like ''.

Indeed this means that the 'defer:' or 'thunk' or special symbol spelling,
has to decide whether the thing being deferred is already itself a deferred
object. If so, just pass along the identical object rather than treat it as
a new expression.

At least that's what would feel most intuitive to me. But I'm deliberately
not pushing a specific syntax. For example, if we didn't want to "reuse"
the spelling 'defer:' for both creating and passing a deferred object, we
could have different spellings.

def f(x=defer: a + b):
a, b = 3, 5
fn2(noeval: x)
return x

... I don't like that spelling, but just showing the concept.

>
___
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/RMHPLSJ3U67I4TCXS4SVSWNDEATHOVDD/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Chris Angelico
On Mon, Oct 25, 2021 at 1:16 AM Zomatree .  wrote:
>
> What would the the syntax for the default be, i would presume just a single 
> expression like a lambda, but what about something like an async function, 
> for example:
> ```py
> async def foo(arg=>await get_arg()):
> ```
> would this work?

That's an open question at the moment, but I suspect that it will be
perfectly acceptable. Same with a yield expression in a generator.

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/QCIQ6G4CBHLJHYRQ6HXV4UHHRRYH6UIE/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Zomatree .
What would the the syntax for the default be, i would presume just a single 
expression like a lambda, but what about something like an async function, for 
example:
```py
async def foo(arg=>await get_arg()):
```
would this work?
___
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/TUPT6HTLLBCBWHZJIJCIPE4EUBDHOLNQ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Deferred evaluation (was: PEP 671: Syntax for late-bound function argument defaults)

2021-10-24 Thread Chris Angelico
On Mon, Oct 25, 2021 at 12:47 AM David Mertz, Ph.D.
 wrote:
>
> On Sun, Oct 24, 2021, 12:20 AM Chris Angelico
>>
>> How would it know to look for a and b inside fn2's scope, instead of looking 
>> for x inside fn2's scope?
>
>
> The same way 'eval("a+b")' knows to look in the local scope when evaluated.
>
> I mean, of course 'x' could be rebound in some scope before it was evaluated. 
> But a "deferred" object itself would simply represent potential computation 
> that may or may not be performed.
>
> If we wanted to use descriptors, and e.g. use 'x.val' rather than plain 'x' , 
> we could do it now with descriptors. But not with plain variable names now.

Not sure I understand. Your example was something like:

def fn2(thing):
a, b = 13, 21
x = 5
print("Thing is:", thing)

def f(x=defer: a + b):
a, b = 3, 5
fn2(defer: x)
return x

So inside f(), "defer: a + b" will look in f's scope and use the
variables a and b from there, but passing a "defer: x" to fn2 will use
x from f's scope, and then a and b from fn2's?

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/BMKPZ7FTIVXE6NVDM2ZS6IB6RWZKATG2/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Steven D'Aprano
On Sun, Oct 24, 2021 at 09:39:27AM -0400, David Mertz, Ph.D. wrote:

> This has been a topic of other threads over the years, and something I've
> wanted at least since I first worked with Dask's 'delayed()' function.

You mean this?

https://docs.dask.org/en/latest/delayed.html



-- 
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/ORMQESE5VKVASQPJYYKZT4VT5E6RYEFC/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: def variable = value

2021-10-24 Thread Jonathan Fine
Hi Serhiy

Thank you for so clearly explaining how names get passed to function and
class constructors.

You also wrote:

> We do not have generalized way to call arbitrary constructor with
> automatically passing __name__, __qualname__ and __module__. And it would
> be convenient.
>
> create namedtuple Point(x, y, z=0)
>  [further examples snipped]


We can already do something similar by writing (not tested)
class Point(Hack): namedtuple = lambda x, y, z=0: None
provided Hack has a suitable value.

I don't see a way to do much better than this, without introducing a new
language keyword. For example allow
signature(x, y, z=0)
to be an EXPRESSION that returns a function signature.

By the way,
class Point(Hack): def namedtuple(x, y, z=0): pass
gives a syntax error at 'def'.
-- 
Jonathan
___
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/CRSD2XZXJTRD4VNPRAUAFPKBELMA2FG3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Steven D'Aprano
On Sun, Oct 24, 2021 at 12:39:38PM +0100, Matt del Valle wrote:

> I'll confess though I'm not a fan of any of the alternate syntaxes. I think
> => works really well, particularly if lambdas in the form: `(*args) =>
> expr` are added at some point in the future

So if we have the arrow shortcut for type hints, and an arrow shortcut 
for lambda, then we can write code like this:

def func(arg:int->int=>x=>x+1)->int:

"I felt a great disturbance in the Force. As if millions of voices cried 
out in terror, and were suddenly silenced."

I think that the likelihood of using an arrow for lambdas and type 
hinting is a major point against this proposed arrow syntax.

And the arrow points the wrong way for an assignment! When we want to 
show a name binding, we write:

name <- value
value -> name

we don't have name->value. Example:

https://www.r-bloggers.com/2018/09/why-do-we-use-arrow-as-an-assignment-operator/

I don't see any language that uses an arrow pointing from the name to 
value for assignment:

https://en.wikipedia.org/wiki/Assignment_%28computer_science%29#Notation

https://i.redd.it/e2kmjoxmy7k61.jpg


-- 
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/63OVHICOY5RUW473ZKD4THQLRQDNIRR3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread David Mertz, Ph.D.
On Sun, Oct 24, 2021, 12:20 AM Chris Angelico

> How would it know to look for a and b inside fn2's scope, instead of
> looking for x inside fn2's scope?
>

The same way 'eval("a+b")' knows to look in the local scope when evaluated.

I mean, of course 'x' could be rebound in some scope before it was
evaluated. But a "deferred" object itself would simply represent potential
computation that may or may not be performed.

If we wanted to use descriptors, and e.g. use 'x.val' rather than plain 'x'
, we could do it now with descriptors. But not with plain variable names
now.
___
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/VAORMIMN7LKBRQ2CSHV732MT7QRYQ2SU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread David Mertz, Ph.D.
On Sun, Oct 24, 2021, 12:25 AM Guido van Rossum

> I am worried that this side-thread about dynamic scopes (which are a
> ridiculous idea IMO) will derail the decent proposal of the PEP.
>

It's really not a suggestion about dynamic scoping but about more
generalized deferred computation.

This has been a topic of other threads over the years, and something I've
wanted at least since I first worked with Dask's 'delayed()' 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/AIL5NVQXHHWACKBYTQYHCSCRFGV5YQ4N/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Abdulla Al Kathiri
Yeah I realized that when I went to my laptop hhh. Hence the previous email 
correcting it. 

> On 24 Oct 2021, at 5:19 PM, Steven D'Aprano  wrote:
> 
> On Sun, Oct 24, 2021 at 04:57:16PM +0400, Abdulla Al Kathiri wrote:
> 
>> def insort_right(a, x, lo=0, hi={len(a)}, *, key=None): … 
> 
> That's already legal syntax for a default value of a set with one 
> element, len(a).
> 
> 
> -- 
> 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/6KWFKBK4UYQBKVVRPHJ6FX7Y67TREAAZ/
> 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 
https://mail.python.org/archives/list/python-ideas@python.org/message/A7GDGIMGG6EFGDN7HFFCIHBN4ZD2RISR/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Abdulla Al Kathiri
Oops I forgot that this could evaluate to a set if “a” was defined beforehand. 
Maybe not a good idea after all. It’s not a good idea to use a mutable object 
anyways a default value.
> On 24 Oct 2021, at 4:57 PM, Abdulla Al Kathiri  
> wrote:
> 
> How about this syntax: 
> 
> def insort_right(a, x, lo=0, hi={len(a)}, *, key=None): … 
> 
> Similar to the expression curly brackets in f-string. If the user didn’t 
> specify a value for hi, the expression between the curly brackets will be 
> evaluated and assigned to hi. 
> Abdulla 
> 
> Sent from my iPhone
> 
>> On 24 Oct 2021, at 4:46 PM, Ricky Teachey  wrote:
>> 
>> 
>> It seems to me that the syntax for late binding could be chosen so as to 
>> leave the possibility of expansion open in the future, and defer (har har) 
>> the entire generalized thunk discussion?
>> 
>> So why not go with syntax like this, where before the ? just represents a 
>> keyword to be bike shedded ("defer", "thunk", "later", ""):
>> 
>> def func(a, b=? a): ...
>> 
>> I kind of like using the ellipses btw; it looks sort of like "later..." to 
>> me: 
>> 
>> def func(a, b = ... a):
>> ...
>> 
>> ___
>> 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/3F2I2N3OO2M34XYOR4SKCA2KQ4FFJBOK/
>> 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 
https://mail.python.org/archives/list/python-ideas@python.org/message/Z5CQH4VMT6GNX73IQ3ZVB6FW5FQXR7WZ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Steven D'Aprano
On Sun, Oct 24, 2021 at 04:57:16PM +0400, Abdulla Al Kathiri wrote:

> def insort_right(a, x, lo=0, hi={len(a)}, *, key=None): … 

That's already legal syntax for a default value of a set with one 
element, len(a).


-- 
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/6KWFKBK4UYQBKVVRPHJ6FX7Y67TREAAZ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Steven D'Aprano
On Sun, Oct 24, 2021 at 10:18:52PM +1100, Steven D'Aprano wrote:

> Find some languages (Lisp, Smalltalk, any others?) and show that they 
> are abused by people in that community.

Oops, sorry I left out a clause.

Find some language **with late-binding defaults** and show that they are 
abused by people in that community.

-- 
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/RSVHFABIG55VRQUBGGA5GPHMK57D72JU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Abdulla Al Kathiri
How about this syntax: 

def insort_right(a, x, lo=0, hi={len(a)}, *, key=None): … 

Similar to the expression curly brackets in f-string. If the user didn’t 
specify a value for hi, the expression between the curly brackets will be 
evaluated and assigned to hi. 
Abdulla 

Sent from my iPhone

> On 24 Oct 2021, at 4:46 PM, Ricky Teachey  wrote:
> 
> 
> It seems to me that the syntax for late binding could be chosen so as to 
> leave the possibility of expansion open in the future, and defer (har har) 
> the entire generalized thunk discussion?
> 
> So why not go with syntax like this, where before the ? just represents a 
> keyword to be bike shedded ("defer", "thunk", "later", ""):
> 
> def func(a, b=? a): ...
> 
> I kind of like using the ellipses btw; it looks sort of like "later..." to 
> me: 
> 
> def func(a, b = ... a):
> ...
> 
> ___
> 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/3F2I2N3OO2M34XYOR4SKCA2KQ4FFJBOK/
> 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 
https://mail.python.org/archives/list/python-ideas@python.org/message/PW3HDVAYG3GRFVQ3HGWE6ILPCNEKP2LJ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Chris Angelico
On Sun, Oct 24, 2021 at 11:45 PM Ricky Teachey  wrote:
>
> It seems to me that the syntax for late binding could be chosen so as to 
> leave the possibility of expansion open in the future, and defer (har har) 
> the entire generalized thunk discussion?
>
> So why not go with syntax like this, where before the ? just represents a 
> keyword to be bike shedded ("defer", "thunk", "later", ""):
>
> def func(a, b=? a): ...
>
> I kind of like using the ellipses btw; it looks sort of like "later..." to me:
>
> def func(a, b = ... a):
> ...
>

I'm not a fan of a keyword to cause late evaluation, for several reasons:

* If it's a hard keyword, then it can't be used anywhere, despite
having meaning only in one specific place.
* If it's a soft keyword, there is confusion based on what's otherwise
a perfectly legal identifier name.
* It's extremely long. At very best, it'll be five letters, and maybe
longer, just to change when something is evaluated. That could easily
be longer than the expression that it's governing.

Keywords are awesome for some situations, but not for this one IMO.

Using ellipsis is kinda cute, but I don't think it'll really help
here, especially as it's a perfectly valid token at that point.
Consider:

def func(a, b=...+a): ...

Is this going to attempt to add Ellipsis and whatever is in the global
a, or is it going to do a unary plus on the first argument?

If thunks are introduced, they would be actual values, which should
mean they can simply use the normal argument defaulting mechanism.
There should be no conflict.

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/5P5DEEMAP662OGQFLP2ECZMZTJPLPMXW/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: def variable = value

2021-10-24 Thread Serhiy Storchaka
24.10.21 15:20, Stephen J. Turnbull пише:
> What do you mean by "constructor" here?  Normally that word refers to
> methods that populate the attributes of instances (in Python, __init__
> and__new__).  But functions and methods don't have such, so you must
> mean something else?

They have. Both function and type classes have constructors and they are
called when a function or class is created. Values of __name__,
__qualname__ and __module__ attributes are directly or indirectly passed
to constructors.

We do not have generalized way to call arbitrary constructor with
automatically passing __name__, __qualname__ and __module__. And it
would be convenient.

create namedtuple Point(x, y, z=0)
create enum Mode(read, write, append)
create NewType UserId(int)
create TypeVar T

___
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/VIRQ44BQKO2ENNL42PCNCVHVLPZMTXYV/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Ricky Teachey
It seems to me that the syntax for late binding could be chosen so as to
leave the possibility of expansion open in the future, and defer (har har)
the entire generalized thunk discussion?

So why not go with syntax like this, where before the ? just represents a
keyword to be bike shedded ("defer", "thunk", "later", ""):

def func(a, b=? a): ...

I kind of like using the ellipses btw; it looks sort of like "later..." to
me:

def func(a, b = ... a):
...
___
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/3F2I2N3OO2M34XYOR4SKCA2KQ4FFJBOK/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: def variable = value

2021-10-24 Thread Stephen J. Turnbull
Jonathan Fine writes:
 > >From my phone.
 > 
 > An important thing about def x and class A is that the strings x and A are
 > made available to the constructor for x and A respectively.

What do you mean by "constructor" here?  Normally that word refers to
methods that populate the attributes of instances (in Python, __init__
and__new__).  But functions and methods don't have such, so you must
mean something else?

 > The same is not true for x=val.

And cannot be, since no construction is involved, just evaluation of
the rhs expression, and binding of the name to the result.

 > 
 > Jonathan
 > ___
 > 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/GMUQMIGOHZGXF5VA6DG5SBM7WQRQBF7O/
 > 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 
https://mail.python.org/archives/list/python-ideas@python.org/message/2FSNZ3FRSFDLWZS24RMLROHN2HGY5LWZ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Chris Angelico
On Sun, Oct 24, 2021 at 9:52 PM Serhiy Storchaka  wrote:
>
> 23.10.21 19:07, Chris Angelico пише:
> > _missing = object()
> > def spaminate(thing, count=_missing):
> > if count is _missing: count = thing.getdefault()
> >
> > Proposal: Proper syntax and support for late-bound argument defaults.
> >
> > def spaminate(thing, count=:thing.getdefault()):
> > ...
>
> Few years ago I proposed a syntax for optional arguments without default
> value:
>
> def spaminate(thing, count=?):
> try:
> count
> except UnboundLocalError:
> count = thing.getdefault()
> ...

Ah yes, I'd forgotten about this proposal.

> It would help in cases in which we now use None or special singleton
> value. It is more general than late-bound arguments, because it can be
> used in cases in which the default argument cannot be expressed, like in
> getattr() and dict.pop().

True, but in the example you give here, I would definitely prefer
"count=>thing.getdefault()".

> The code for initialization of the default value is something
> complicated, but we can introduce special syntax for it:
>
> if unset count:
> count = thing.getdefault()
>
> or even
>
> count ?= thing.getdefault()

This is the perfect way to stir the pot on the None-coalescing
discussion, because now you're looking at a very real concept of null
value :)

(Although there's no way to return this null value from a function or
pass it to another, so the state of being unbound should be local to a
single code unit.)

> > 1) Inspecting the function would reveal the source code for the late-bound 
> > value
> > 2) There is no value which can be passed as an argument to achieve the
> > same effect
>
> This is the largest problem of both ideas. The inspect module has no way
> to represent optional arguments without default value, and any solution
> will break user code which is not ready for this feature.

There kinda sorta is a way to do it, at least for keyword arguments:

def func_left(x, y=>len(x)): ...

def func_right(x, y=?):
if unset y: y = {}
else y = {"y": y}
return func_left(-x, **y)

But if there were a value that could be passed as an argument to
indicate "no value", then we'd come across the same problem of using
None as a default: sometimes, literally any value could be valid, and
we still need to signal the absence of a value.

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/KGBKQFBJA66T2XR5DM4EWW74GNAJ56AH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Matt del Valle
Agreed on the point about PEP 661, if this is accepted I don't think it
will have much to offer.

For what it's worth I'm a very strong +1 on PEP 671 as it stands. Thanks
for showing me something I didn't even know I wanted Chris :)

I'll confess though I'm not a fan of any of the alternate syntaxes. I think
=> works really well, particularly if lambdas in the form: `(*args) =>
expr` are added at some point in the future, because it establishes some
common semantics between both uses of the => operator (namely, deferred
code execution. In both cases the expression on the right of the => isn't
expected to execute when the block itself is executed, but rather at some
future point when something is called).

I'm not a big fan of =: because we already have := and I can imagine it
being quite easy for people to not remember which way around each one is
(and it's just generally more effortful to visually parse), since neither
of them has a particularly strong intuitive meaning. By contrast => looks
visually like an arrow, while <= and >= have the advantage that their
ordering corresponds to how you would say it out loud or in your head (less
than or equal to/greater than or equal to), so I don't think those symbols
have the same issue.

I also don't love ?= because ? is one of the last few reasonable symbols we
have available for new syntax (*cough* backtick *cough*, not even once).
Whether it ends up being used for something like PEP 505: None-aware
operators (if that is ever resurrected, I can only dream) or some other
future feature we have yet to imagine, I'd prefer the ? symbol remain
available without any baggage. I don't think the rationale for this PEP (as
much as I agree with it) is quite strong enough to use it up.

Anyways, I'm really hoping this gets accepted. Awesome proposal!


On Sun, Oct 24, 2021 at 11:36 AM Paul Moore  wrote:

> This should probably reference PEP 661 (Sentinel Values) which is
> being discussed on Discourse:
> https://discuss.python.org/t/pep-661-sentinel-values/9126
>
> It's a different proposal, but one of the major motivating use cases
> (if not the only one) for sentinels is handling function default
> values that can't be expressed at definition times. So how the two
> proposals interact should be discussed *somewhere*, IMO.
>
> Personally I'd choose to support this proposal, and take the view that
> it weakens the need for PEP 661 to the point where I'd prefer not to
> bother with that proposal.
>
> Paul
>
> On Sun, 24 Oct 2021 at 01:15, Chris Angelico  wrote:
> >
> > Incorporates comments from the thread we just had.
> >
> > Is anyone interested in coauthoring this with me? Anyone who has
> > strong interest in seeing this happen - whether you've been around the
> > Python lists for years, or you're new and interested in getting
> > involved for the first time, or anywhere in between!
> >
> > https://www.python.org/dev/peps/pep-0671/
> >
> > PEP: 671
> > Title: Syntax for late-bound function argument defaults
> > Author: Chris Angelico 
> > Status: Draft
> > Type: Standards Track
> > Content-Type: text/x-rst
> > Created: 24-Oct-2021
> > Python-Version: 3.11
> > Post-History: 24-Oct-2021
> >
> >
> > Abstract
> > 
> >
> > Function parameters can have default values which are calculated during
> > function definition and saved. This proposal introduces a new form of
> > argument default, defined by an expression to be evaluated at function
> > call time.
> >
> >
> > Motivation
> > ==
> >
> > Optional function arguments, if omitted, often have some sort of logical
> > default value. When this value depends on other arguments, or needs to be
> > reevaluated each function call, there is currently no clean way to state
> > this in the function header.
> >
> > Currently-legal idioms for this include::
> >
> > # Very common: Use None and replace it in the function
> > def bisect_right(a, x, lo=0, hi=None, *, key=None):
> > if hi is None:
> > hi = len(a)
> >
> > # Also well known: Use a unique custom sentinel object
> > _USE_GLOBAL_DEFAULT = object()
> > def connect(timeout=_USE_GLOBAL_DEFAULT):
> > if timeout is _USE_GLOBAL_DEFAULT:
> > timeout = default_timeout
> >
> > # Unusual: Accept star-args and then validate
> > def add_item(item, *optional_target):
> > if not optional_target:
> > target = []
> > else:
> > target = optional_target[0]
> >
> > In each form, ``help(function)`` fails to show the true default value.
> Each
> > one has additional problems, too; using ``None`` is only valid if None
> is not
> > itself a plausible function parameter, the custom sentinel requires a
> global
> > constant; and use of star-args implies that more than one argument could
> be
> > given.
> >
> > Specification
> > =
> >
> > Function default arguments can be defined using the new ``=>`` notation::
> >
> > def bisect_right(a, x, lo=0, hi=>len(a), *, 

[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Chris Angelico
On Sun, Oct 24, 2021 at 9:34 PM Paul Moore  wrote:
>
> This should probably reference PEP 661 (Sentinel Values) which is
> being discussed on Discourse:
> https://discuss.python.org/t/pep-661-sentinel-values/9126
>
> It's a different proposal, but one of the major motivating use cases
> (if not the only one) for sentinels is handling function default
> values that can't be expressed at definition times. So how the two
> proposals interact should be discussed *somewhere*, IMO.
>
> Personally I'd choose to support this proposal, and take the view that
> it weakens the need for PEP 661 to the point where I'd prefer not to
> bother with that proposal.
>

Good point; I'll add a reference.

When I was searching the stdlib for examples of different arg-passing
idioms, I came across quite a number of uses of object() which weren't
used for argument defaults, so while it's true that PEP 661 would lose
one use-case if 671 is accepted, I still think that 661 would have
plenty of value.

The specific example that PEP 661 cites - traceback.print_exception()
- wouldn't be able to be transformed using PEP 671 alternate defaults,
unless the API were to be changed somewhat. You can't specify the
traceback while leaving the value at its default, and PEP 671 is
stateless with regard to multiple parameters.

(That said, though: traceback.format_exception_only() could benefit
from PEP 671.)

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/NY3QTPF4V2R4XBONUVPTCJXSWVFO7FYS/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Steven D'Aprano
On Sat, Oct 23, 2021 at 11:47:59PM -0700, Brendan Barnwell wrote:

>   It's true that any feature can be abused, but I think this 
>   temptation to shoehorn function logic into the argument list will be 
> more 
> likely to result in unwieldy signatures than the current situation.

That should be easy to demonstrate.

Find some languages (Lisp, Smalltalk, any others?) and show that they 
are abused by people in that community.


-- 
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/WLIXBKKIYWZDIBEFCNTZ3Z5EWNULDZB6/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Serhiy Storchaka
23.10.21 19:07, Chris Angelico пише:
> _missing = object()
> def spaminate(thing, count=_missing):
> if count is _missing: count = thing.getdefault()
> 
> Proposal: Proper syntax and support for late-bound argument defaults.
> 
> def spaminate(thing, count=:thing.getdefault()):
> ...

Few years ago I proposed a syntax for optional arguments without default
value:

def spaminate(thing, count=?):
try:
count
except UnboundLocalError:
count = thing.getdefault()
...

It would help in cases in which we now use None or special singleton
value. It is more general than late-bound arguments, because it can be
used in cases in which the default argument cannot be expressed, like in
getattr() and dict.pop().

The code for initialization of the default value is something
complicated, but we can introduce special syntax for it:

if unset count:
count = thing.getdefault()

or even

count ?= thing.getdefault()

> 1) Inspecting the function would reveal the source code for the late-bound 
> value
> 2) There is no value which can be passed as an argument to achieve the
> same effect

This is the largest problem of both ideas. The inspect module has no way
to represent optional arguments without default value, and any solution
will break user code which is not ready for this feature.

___
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/XRRS5ZAF4YG2P6U26BW3DJEGPBFUXXED/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671: Syntax for late-bound function argument defaults

2021-10-24 Thread Paul Moore
This should probably reference PEP 661 (Sentinel Values) which is
being discussed on Discourse:
https://discuss.python.org/t/pep-661-sentinel-values/9126

It's a different proposal, but one of the major motivating use cases
(if not the only one) for sentinels is handling function default
values that can't be expressed at definition times. So how the two
proposals interact should be discussed *somewhere*, IMO.

Personally I'd choose to support this proposal, and take the view that
it weakens the need for PEP 661 to the point where I'd prefer not to
bother with that proposal.

Paul

On Sun, 24 Oct 2021 at 01:15, Chris Angelico  wrote:
>
> Incorporates comments from the thread we just had.
>
> Is anyone interested in coauthoring this with me? Anyone who has
> strong interest in seeing this happen - whether you've been around the
> Python lists for years, or you're new and interested in getting
> involved for the first time, or anywhere in between!
>
> https://www.python.org/dev/peps/pep-0671/
>
> PEP: 671
> Title: Syntax for late-bound function argument defaults
> Author: Chris Angelico 
> Status: Draft
> Type: Standards Track
> Content-Type: text/x-rst
> Created: 24-Oct-2021
> Python-Version: 3.11
> Post-History: 24-Oct-2021
>
>
> Abstract
> 
>
> Function parameters can have default values which are calculated during
> function definition and saved. This proposal introduces a new form of
> argument default, defined by an expression to be evaluated at function
> call time.
>
>
> Motivation
> ==
>
> Optional function arguments, if omitted, often have some sort of logical
> default value. When this value depends on other arguments, or needs to be
> reevaluated each function call, there is currently no clean way to state
> this in the function header.
>
> Currently-legal idioms for this include::
>
> # Very common: Use None and replace it in the function
> def bisect_right(a, x, lo=0, hi=None, *, key=None):
> if hi is None:
> hi = len(a)
>
> # Also well known: Use a unique custom sentinel object
> _USE_GLOBAL_DEFAULT = object()
> def connect(timeout=_USE_GLOBAL_DEFAULT):
> if timeout is _USE_GLOBAL_DEFAULT:
> timeout = default_timeout
>
> # Unusual: Accept star-args and then validate
> def add_item(item, *optional_target):
> if not optional_target:
> target = []
> else:
> target = optional_target[0]
>
> In each form, ``help(function)`` fails to show the true default value. Each
> one has additional problems, too; using ``None`` is only valid if None is not
> itself a plausible function parameter, the custom sentinel requires a global
> constant; and use of star-args implies that more than one argument could be
> given.
>
> Specification
> =
>
> Function default arguments can be defined using the new ``=>`` notation::
>
> def bisect_right(a, x, lo=0, hi=>len(a), *, key=None):
> def connect(timeout=>default_timeout):
> def add_item(item, target=>[]):
>
> The expression is saved in its source code form for the purpose of inspection,
> and bytecode to evaluate it is prepended to the function's body.
>
> Notably, the expression is evaluated in the function's run-time scope, NOT the
> scope in which the function was defined (as are early-bound defaults). This
> allows the expression to refer to other arguments.
>
> Self-referential expressions will result in UnboundLocalError::
>
> def spam(eggs=>eggs): # Nope
>
> Multiple late-bound arguments are evaluated from left to right, and can refer
> to previously-calculated values. Order is defined by the function, regardless
> of the order in which keyword arguments may be passed.
>
>
> Choice of spelling
> --
>
> Our chief syntax proposal is ``name=>expression`` -- our two syntax proposals
> ... ahem. Amongst our potential syntaxes are::
>
> def bisect(a, hi=>len(a)):
> def bisect(a, hi=:len(a)):
> def bisect(a, hi?=len(a)):
> def bisect(a, hi!=len(a)):
> def bisect(a, hi=\len(a)):
> def bisect(a, hi=`len(a)`):
> def bisect(a, hi=@len(a)):
>
> Since default arguments behave largely the same whether they're early or late
> bound, the preferred syntax is very similar to the existing early-bind syntax.
> The alternatives offer little advantage over the preferred one.
>
> How to Teach This
> =
>
> Early-bound default arguments should always be taught first, as they are the
> simpler and more efficient way to evaluate arguments. Building on them, late
> bound arguments are broadly equivalent to code at the top of the function::
>
> def add_item(item, target=>[]):
>
> # Equivalent pseudocode:
> def add_item(item, target=):
> if target was omitted: target = []
>
>
> Open Issues
> ===
>
> - yield/await? Will they cause problems? Might end up being a non-issue.
>
> - annotations? They go before the default, so is there any way an anno could
>   

[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Brendan Barnwell

On 2021-10-23 23:33, Steven D'Aprano wrote:

On Sat, Oct 23, 2021 at 08:29:54PM -0700, Brendan Barnwell wrote:


For me the biggest problem with this idea is that it only handles a
subset of cases, namely those that can be expressed as an expression
inlined into the function definition.


True. But that's equally true for default values under early binding.
Would you say that existing syntax for default values is problematic
because it only covers the 90% of cases where the default value can be
computed from an expression?

If push comes to shove, we can always write a helper function.



This subset is too small, because
we'll still have to write code in the function body for cases where the
default depends on more complex logic.  But it is also too large,
because it will encourage people to cram complex expressions into the
function definition.


Just like they do now?


	I understand your point, but there is an important difference between 
the current situation and the proposal.  Right now, the function 
definition executes in the enclosing scope.  That means that there is 
nothing you can do in a default-argument expression that you can't do by 
assigning to a variable in a separate line (or lines) before defining 
the function.  But with this proposal, the function definition will gain 
the new ability to express logic that executes in the function body 
environment, with the restriction that it be only a single expression.


	It's true that any feature can be abused, but I think this temptation 
to shoehorn function logic into the argument list will be more likely to 
result in unwieldy signatures than the current situation.


--
Brendan Barnwell
"Do not follow where the path may lead.  Go, instead, where there is no 
path, and leave a trail."

   --author unknown
___
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/OYUT3DI7J57GX3EE4NKTL7L3NVSNCD5N/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Ben Rudiak-Gould
On Sat, Oct 23, 2021 at 11:53 PM Steven D'Aprano 
wrote:

> If we had thunks, that would give us late binding for free:
>
> def bisect(a, x, lo=0, hi=thunk len(a), *, key=None)
>

I'm unclear on exactly what the semantics of a thunk would be, but I don't
see how it could do what you want here. In an ordinary default value, the
"a" in "len(a)" refers to a variable of that name in the enclosing scope,
not the argument of bisect. A generic delayed-evaluation mechanism wouldn't
(shouldn't) change that.
___
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/TUOGJLRRYHBGRJRTYVT4YXPLNY2JJW6U/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Chris Angelico
On Sun, Oct 24, 2021 at 5:53 PM Steven D'Aprano  wrote:
>
> On Sun, Oct 24, 2021 at 02:09:59PM +1100, Chris Angelico wrote:
>
> > The biggest problem with thunks is knowing when to trigger evaluation.
>
> I think Algol solved that problem by having thunks a purely internal
> mechanism, not a first-class value that users could store or pass
> around.

If you can't pass them around, then how are they different from what's
proposed here? They are simply expressions that get evaluated a bit
later. You potentially win on performance if it's expensive, but you
lose on debuggability when errors happen further down and less
consistently, and otherwise, it's exactly the same thing.

> If we had thunks, that would give us late binding for free:
>
> def bisect(a, x, lo=0, hi=thunk len(a), *, key=None)
>
> Aaaand we're done. So thunks would make this PEP obsolete.
>
> But if thunks are implausible, too hard, or would have too high a cost,
> then this PEP remains less ambitious and therefore easier.
>

Where else would you use thunks? I think it's exactly as ambitious, if
indeed they can't be stored or passed around.

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/UUCMBELGELSD73ONYH54FCGI6JCCSXBA/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Steven D'Aprano
On Sun, Oct 24, 2021 at 02:09:59PM +1100, Chris Angelico wrote:

> The biggest problem with thunks is knowing when to trigger evaluation.

I think Algol solved that problem by having thunks a purely internal 
mechanism, not a first-class value that users could store or pass 
around.


> We already have functions if you want to be explicit about that:

Yes, if we are satisfied with purely manually evaluating thunks. The 
point of a thunk though is that the interpreter knows when to evaluate 
it, you don't have to think about it.


> Thunks would be another great feature, but I think they're orthogonal 
> to this.

If we had thunks, that would give us late binding for free:

def bisect(a, x, lo=0, hi=thunk len(a), *, key=None)

Aaaand we're done. So thunks would make this PEP obsolete.

But if thunks are implausible, too hard, or would have too high a cost, 
then this PEP remains less ambitious and therefore easier.


-- 
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/WG36UOCBSR7RKWGHDX36OK6CHGSSSMG6/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Steven D'Aprano
On Sat, Oct 23, 2021 at 08:29:54PM -0700, Brendan Barnwell wrote:

>   For me the biggest problem with this idea is that it only handles a
> subset of cases, namely those that can be expressed as an expression
> inlined into the function definition.

True. But that's equally true for default values under early binding. 
Would you say that existing syntax for default values is problematic 
because it only covers the 90% of cases where the default value can be 
computed from an expression?

If push comes to shove, we can always write a helper function.


> This subset is too small, because
> we'll still have to write code in the function body for cases where the
> default depends on more complex logic.  But it is also too large,
> because it will encourage people to cram complex expressions into the
> function definition.

Just like they do now?

I think people can write bad code regardless of the features available, 
but I don't think that adding late binding will particularly make that 
tendency worse. Most uses of late binding will be pretty simple:

- mutable literals like [] and {};

- length of another argument (like the bisect example);

- references to an attribute of self;

- call out to another function.

I don't think that there is good reason to believe that adding late 
binding will cause a large increase in the amount of overly complex 
default values.

As you say, they are limited to a single expression, so the really 
complex blocks will have to stay inside the body of the function where 
they belong. And we have thirty years of default values, and no sign 
that people abuse them by writing lots of horrific defaults:

def func(arg=sum(min(seq) for seq in [[LOOKUP[key]]+list(elements)  
 for key, elements in zip(map(Mapper(spam, eggs), keys),
 iterable_of_sets) if condition(key)] if len(seq) > 5)):
...

People just don't do that sort of thing in anywhere near enough numbers 
to worry about them doing it just because we have late binding.

And if they do?

"People will write crappy code" is a social problem, not a technology 
problem, which is best solved socially, using code reviews, linters, a 
quick application of the Clue Bat to the offending coder's head, etc.


>   I would prefer to see this situation handled as part of a 
>   larger-scale
> change of adding some kind of "inline lambda" which executes directly in
> the calling scope.

That would be what I called a "thunk" in two posts now, stealing the 
term from Algol.

It would be nice if one of the core devs who understand the deep 
internals of the interpreter could comment on whether that sort of 
delayed evaluation of an expression is even plausible for Python.

If it is, then I agree: we should focus on a general thunk mechanism, 
which would then give us late binding defaults for free, plus many more 
interesting use-cases.

(Somewhere in my hard drive I have a draft proto-PEP regarding this.)

But if it is not plausible, then a more limited mechanism for late bound 
defaults will, I think, be a useful feature that improves the experience 
of writing functions.

We already document functions like this:

def bisect(a, x, lo=0, hi=len(a))

It would be an improvement if we could write them like that too.


-- 
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/REVRTYICAKVOZRV2X5PPOY2U5XUY5RQG/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Syntax for late-bound arguments

2021-10-24 Thread Chris Angelico
On Sun, Oct 24, 2021 at 3:51 PM Brendan Barnwell  wrote:
>
> On 2021-10-23 09:07, Chris Angelico wrote:
> > Proposal: Proper syntax and support for late-bound argument defaults.
> >
> > def spaminate(thing, count=:thing.getdefault()):
> >  ...
>
> I'm -1 on it.
>
> For me the biggest problem with this idea is that it only handles a
> subset of cases, namely those that can be expressed as an expression
> inlined into the function definition.  This subset is too small, because
> we'll still have to write code in the function body for cases where the
> default depends on more complex logic.  But it is also too large,
> because it will encourage people to cram complex expressions into the
> function definition.
> ...
> Also, insofar as glancing at the function signature is useful, I
> suspect that putting this change in will *also* lead to help() being
> unhelpful, because, as I mentioned above, if the default uses anything
> but the most trivial logic, the signature will become cluttered with
> stuff that ought to be separated out as actual logic.

These two considerations, together, are the exact push that
programmers need: keep the expression short, don't cram everything
into the function definition. It's like writing a list comprehension;
technically you can put any expression into the body of it, but it's
normally going to be short enough to not get unwieldy.

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/3WSNUFX4WS27HG75AYRODIKN7N5DIC7C/
Code of Conduct: http://python.org/psf/codeofconduct/