Re: [Python-ideas] globals should accept parenteses for extending beyond 1 line

2017-01-23 Thread Steven D'Aprano
On Mon, Jan 23, 2017 at 09:18:54PM +, João Matos wrote:

> Why should I repeat global if I can use the line separation character \ 
> (like I mentioned on my 1st email) or parentheses as I suggested?

That's the wrong question.

The right question is, why should the Python language be made larger, 
more complicated, with more lines of code, to support parentheses in 
global declarations, when there are already two perfectly good 
alternatives?

global spam
global eggs


global spam, \
   eggs


Even if it only adds one extra line of code to the Python interpreter, 
that's still a cost. But it will add more than that: it will require the 
implementation, tests and documentation. And all other Python 
interpretations will need to do the same: IronPython, Jython, PyPy, µPy, 
Stackless, Nuitka and possibly more. And it is a new feature that people 
have to learn.

Every new feature has a cost. Even if the cost is tiny, the question 
is, will the benefit be greater than the cost?

Supporting parentheses in from...import statements has major benefit:

from deep.package.name import (spam,
eggs, cheese, foo, bar, baz,
fe, fi, fo, fum)

is a big improvement over:

from deep.package.name import spam, eggs, cheese
from deep.package.name import foo, bar, baz
from deep.package.name import fe, fi, fo, fum

for at least two reasons: better efficiency, and DRY (Don't Repeat 
Yourself) with the package name.

But for globals, neither reason applies: global statements are a 
compile-time declaration, not an executable statement, so efficiency 
isn't relevant, and there is no significant DRY issue with repeating the 
keyword global itself.

So the question here is not "why shouldn't we allow parentheses?" but 
"why should we allow parentheses?"

If your answer is just "I think it looks nicer", you probably won't find 
a lot of people who agree, and even fewer people who agree enough to 
actually do the work of writing the patch, the tests and the 
documentation.

So that comes down to the most important question of all:

- are you volunteering to do the work yourself?

If there are no strong objections to adding this feature, it might be 
easier to get a core developer to offer to review your work and check it 
in, than to get a core developer to add the feature themselves.

I don't dislike this proposed feature. Nor do I like it. I would 
probably never use it: it is very rare for me to use global at all, and 
even rarer to use more than one or two globals. But if somebody else did 
the work, I wouldn't strongly object to it.


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


Re: [Python-ideas] globals should accept parenteses for extending beyond 1 line

2017-01-23 Thread Ethan Furman

On 01/23/2017 01:18 PM, João Matos wrote:


Why should I repeat global if I can use the line separation character \
 (like I mentioned on my 1st email) or parentheses as I suggested?


Because prefixing each line with global is more readable than either \ or ( )?  
At least to me.  ;)

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

Re: [Python-ideas] globals should accept parenteses for extending beyond 1 line

2017-01-23 Thread MRAB

On 2017-01-23 20:09, Nick Timkovich wrote:

Related and probably more common is the need for the line-continuation
operator for long/multiple context managers with "with". I assume that's
come up before, but was it also just a low priority rather than any
technical reason?

It has come up before, and there is a technical reason, namely the 
syntactic ambiguity when parsing. Not impossible to fix, but probably 
not worth the added complexity.



On Mon, Jan 23, 2017 at 1:53 PM, Brett Cannon > wrote:

Actually multi-line import doesn't work:

File ".\Untitled.py", line 1
import (tokenize,
   ^
SyntaxError: invalid syntax

I think you're getting this mixed up with parentheses being allowed
in `from ... import (...)` syntax. So unless there is another
single-word keyword that allows multi-line arguments using
parentheses I don't think there's an inconsistency here.

Plus, as Guido pointed out, the current syntax isn't preventing you
from doing something you can already do. So if you want to add
parentheses support to global, nonlocal, and import, you can propose
a patch, but it's not a priority to solve without someone providing
a solution since it doesn't open up anything new for something
people don't use on a regular basis.


On Mon, 23 Jan 2017 at 11:39 João Matos > wrote:

Hello,

You are correct, my mistake. I should have written global and
not globals.

The purpose of using parentheses on the import statement is not
(in my
view) for operational efficiency but for appearance/cleaness.
The same applies to using it to global.

One does not need to have 10 global vars. It may have to do with var
name length and the 79 max line length.

This is an example from my one of my programs:
global existing_graph, expected_duration_in_sec, file_size, \
 file_mtime, no_change_counter

Anyway, the use of global being rare is of no concern. The point
of my
suggestion is standardization.
My opinion is that a standard language is easier to learn (and
teach)
than one that has different syntax for the same issue, depending
on the
statement.

In short, if the recommended multi-line use for import is

import (a, b,
 c)

instead of

import a, b, \
 c

Then the same should apply to global.


Best regards,

JM




On 23-01-2017 19:25, Terry Reedy wrote:
> On 1/23/2017 1:43 PM, João Matos wrote:
>> Hello,
>>
>> I would like to suggest that globals should follow the
existing rule
>> (followed by the import statement, the if statement and in
other places)
>> for extending beyond 1 line using parentheses.
>> Like this:
>> globals (var_1, var_2,
>> var_3)
>>
>> instead of what must be done now, which is:
>> globals var_1, var_2 \
>> var_3
>
> The declaration keyword is 'global'; 'globals' is the built-in
> function.  In any case
>
> global var_1, var_2
> global var_3
>
> works fine.  There is no connection between the names and,
unlike with
> import, no operational efficiency is gained by mashing the
statements
> together.
>
> This issue should be rare.  The global statement is only
needed when
> one is rebinding global names within a function*.  If a function
> rebinds 10 different global names, the design should probably be
> re-examined.
>
> * 'global' at class scope seems useless.
>
> a = 0
> class C:
> a = 1
>
> has the same effect as
> a = 0
> a = 1
> class C: pass
>


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

Re: [Python-ideas] globals should accept parenteses for extending beyond 1 line

2017-01-23 Thread João Matos

Hello,

The subject of this topic is a suggestion about the language and not the 
programming paradigm/style.


Why should I repeat global if I can use the line separation character \ 
(like I mentioned on my 1st email) or parentheses as I suggested?


"global existing_graph, expected_duration # "in_sec" is unnecessary"
No it is not unnecessary unless sec is the only unit you use (in this 
case we have several units of duration and thus it is necessary).


Best regards,

JM



On 23-01-2017 20:24, Chris Angelico wrote:

On Tue, Jan 24, 2017 at 6:37 AM, João Matos  wrote:

One does not need to have 10 global vars. It may have to do with var name
length and the 79 max line length.

This is an example from my one of my programs:
global existing_graph, expected_duration_in_sec, file_size, \
 file_mtime, no_change_counter


I think you're already running into serious design concerns here. Why
are file_size and file_mtime global? Perhaps a better design would
involve a class, where this function would become a method, and those
globals become "self.file_size" and "self.file_mtime". Then you can
have a single global instance of that class for now, but if ever you
need two of them, it's trivially easy. You encapsulate all of this
global state into a coherent package.

But if you MUST use globals, I would split the lines according to purpose:

global existing_graph, expected_duration # "in_sec" is unnecessary
global file_size, file_mtime
global no_change_counter # also probably needs a new name

That way, you're unlikely to run into the 80-char limit.

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


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

Re: [Python-ideas] globals should accept parenteses for extending beyond 1 line

2017-01-23 Thread João Matos

Hello,

I understand.
Python sources are very large. Any pointers to which file defines the 
global statement syntax?


Best regards,

JM


On 23-01-2017 19:53, Brett Cannon wrote:

Actually multi-line import doesn't work:

File ".\Untitled.py", line 1
import (tokenize,
   ^
SyntaxError: invalid syntax

I think you're getting this mixed up with parentheses being allowed in 
`from ... import (...)` syntax. So unless there is another single-word 
keyword that allows multi-line arguments using parentheses I don't 
think there's an inconsistency here.


Plus, as Guido pointed out, the current syntax isn't preventing you 
from doing something you can already do. So if you want to add 
parentheses support to global, nonlocal, and import, you can propose a 
patch, but it's not a priority to solve without someone providing a 
solution since it doesn't open up anything new for something people 
don't use on a regular basis.



On Mon, 23 Jan 2017 at 11:39 João Matos > wrote:


Hello,

You are correct, my mistake. I should have written global and not
globals.

The purpose of using parentheses on the import statement is not (in my
view) for operational efficiency but for appearance/cleaness.
The same applies to using it to global.

One does not need to have 10 global vars. It may have to do with var
name length and the 79 max line length.

This is an example from my one of my programs:
global existing_graph, expected_duration_in_sec, file_size, \
 file_mtime, no_change_counter

Anyway, the use of global being rare is of no concern. The point of my
suggestion is standardization.
My opinion is that a standard language is easier to learn (and teach)
than one that has different syntax for the same issue, depending
on the
statement.

In short, if the recommended multi-line use for import is

import (a, b,
 c)

instead of

import a, b, \
 c

Then the same should apply to global.


Best regards,

JM




On 23-01-2017 19:25, Terry Reedy wrote:
> On 1/23/2017 1:43 PM, João Matos wrote:
>> Hello,
>>
>> I would like to suggest that globals should follow the existing
rule
>> (followed by the import statement, the if statement and in
other places)
>> for extending beyond 1 line using parentheses.
>> Like this:
>> globals (var_1, var_2,
>> var_3)
>>
>> instead of what must be done now, which is:
>> globals var_1, var_2 \
>> var_3
>
> The declaration keyword is 'global'; 'globals' is the built-in
> function.  In any case
>
> global var_1, var_2
> global var_3
>
> works fine.  There is no connection between the names and,
unlike with
> import, no operational efficiency is gained by mashing the
statements
> together.
>
> This issue should be rare.  The global statement is only needed when
> one is rebinding global names within a function*.  If a function
> rebinds 10 different global names, the design should probably be
> re-examined.
>
> * 'global' at class scope seems useless.
>
> a = 0
> class C:
> a = 1
>
> has the same effect as
> a = 0
> a = 1
> class C: pass
>

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



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

Re: [Python-ideas] globals should accept parenteses for extending beyond 1 line

2017-01-23 Thread Chris Angelico
On Tue, Jan 24, 2017 at 6:37 AM, João Matos  wrote:
> One does not need to have 10 global vars. It may have to do with var name
> length and the 79 max line length.
>
> This is an example from my one of my programs:
> global existing_graph, expected_duration_in_sec, file_size, \
> file_mtime, no_change_counter
>

I think you're already running into serious design concerns here. Why
are file_size and file_mtime global? Perhaps a better design would
involve a class, where this function would become a method, and those
globals become "self.file_size" and "self.file_mtime". Then you can
have a single global instance of that class for now, but if ever you
need two of them, it's trivially easy. You encapsulate all of this
global state into a coherent package.

But if you MUST use globals, I would split the lines according to purpose:

global existing_graph, expected_duration # "in_sec" is unnecessary
global file_size, file_mtime
global no_change_counter # also probably needs a new name

That way, you're unlikely to run into the 80-char limit.

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

Re: [Python-ideas] globals should accept parenteses for extending beyond 1 line

2017-01-23 Thread Nick Timkovich
Related and probably more common is the need for the line-continuation
operator for long/multiple context managers with "with". I assume that's
come up before, but was it also just a low priority rather than any
technical reason?

On Mon, Jan 23, 2017 at 1:53 PM, Brett Cannon  wrote:

> Actually multi-line import doesn't work:
>
> File ".\Untitled.py", line 1
> import (tokenize,
>^
> SyntaxError: invalid syntax
>
> I think you're getting this mixed up with parentheses being allowed in
> `from ... import (...)` syntax. So unless there is another single-word
> keyword that allows multi-line arguments using parentheses I don't think
> there's an inconsistency here.
>
> Plus, as Guido pointed out, the current syntax isn't preventing you from
> doing something you can already do. So if you want to add parentheses
> support to global, nonlocal, and import, you can propose a patch, but it's
> not a priority to solve without someone providing a solution since it
> doesn't open up anything new for something people don't use on a regular
> basis.
>
>
> On Mon, 23 Jan 2017 at 11:39 João Matos  wrote:
>
>> Hello,
>>
>> You are correct, my mistake. I should have written global and not globals.
>>
>> The purpose of using parentheses on the import statement is not (in my
>> view) for operational efficiency but for appearance/cleaness.
>> The same applies to using it to global.
>>
>> One does not need to have 10 global vars. It may have to do with var
>> name length and the 79 max line length.
>>
>> This is an example from my one of my programs:
>> global existing_graph, expected_duration_in_sec, file_size, \
>>  file_mtime, no_change_counter
>>
>> Anyway, the use of global being rare is of no concern. The point of my
>> suggestion is standardization.
>> My opinion is that a standard language is easier to learn (and teach)
>> than one that has different syntax for the same issue, depending on the
>> statement.
>>
>> In short, if the recommended multi-line use for import is
>>
>> import (a, b,
>>  c)
>>
>> instead of
>>
>> import a, b, \
>>  c
>>
>> Then the same should apply to global.
>>
>>
>> Best regards,
>>
>> JM
>>
>>
>>
>>
>> On 23-01-2017 19:25, Terry Reedy wrote:
>> > On 1/23/2017 1:43 PM, João Matos wrote:
>> >> Hello,
>> >>
>> >> I would like to suggest that globals should follow the existing rule
>> >> (followed by the import statement, the if statement and in other
>> places)
>> >> for extending beyond 1 line using parentheses.
>> >> Like this:
>> >> globals (var_1, var_2,
>> >> var_3)
>> >>
>> >> instead of what must be done now, which is:
>> >> globals var_1, var_2 \
>> >> var_3
>> >
>> > The declaration keyword is 'global'; 'globals' is the built-in
>> > function.  In any case
>> >
>> > global var_1, var_2
>> > global var_3
>> >
>> > works fine.  There is no connection between the names and, unlike with
>> > import, no operational efficiency is gained by mashing the statements
>> > together.
>> >
>> > This issue should be rare.  The global statement is only needed when
>> > one is rebinding global names within a function*.  If a function
>> > rebinds 10 different global names, the design should probably be
>> > re-examined.
>> >
>> > * 'global' at class scope seems useless.
>> >
>> > a = 0
>> > class C:
>> > a = 1
>> >
>> > has the same effect as
>> > a = 0
>> > a = 1
>> > class C: pass
>> >
>>
>> ___
>> Python-ideas mailing list
>> Python-ideas@python.org
>> https://mail.python.org/mailman/listinfo/python-ideas
>> Code of Conduct: http://python.org/psf/codeofconduct/
>
>
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Re: [Python-ideas] globals should accept parenteses for extending beyond 1 line

2017-01-23 Thread Stephan Houben
For what it's worth, I normally just do:

global a
global b

But I've never needed more than two.
I think if you need more, then there is a serious style issue. That it
looks syntactically ugly is a feature.

Perhaps we should deprecate the comma in global ;-) .

Stephan

Op 23 jan. 2017 8:38 p.m. schreef "João Matos" :

> Hello,
>
> You are correct, my mistake. I should have written global and not globals.
>
> The purpose of using parentheses on the import statement is not (in my
> view) for operational efficiency but for appearance/cleaness.
> The same applies to using it to global.
>
> One does not need to have 10 global vars. It may have to do with var name
> length and the 79 max line length.
>
> This is an example from my one of my programs:
> global existing_graph, expected_duration_in_sec, file_size, \
> file_mtime, no_change_counter
>
> Anyway, the use of global being rare is of no concern. The point of my
> suggestion is standardization.
> My opinion is that a standard language is easier to learn (and teach) than
> one that has different syntax for the same issue, depending on the
> statement.
>
> In short, if the recommended multi-line use for import is
>
> import (a, b,
> c)
>
> instead of
>
> import a, b, \
> c
>
> Then the same should apply to global.
>
>
> Best regards,
>
> JM
>
>
>
>
> On 23-01-2017 19:25, Terry Reedy wrote:
>
>> On 1/23/2017 1:43 PM, João Matos wrote:
>>
>>> Hello,
>>>
>>> I would like to suggest that globals should follow the existing rule
>>> (followed by the import statement, the if statement and in other places)
>>> for extending beyond 1 line using parentheses.
>>> Like this:
>>> globals (var_1, var_2,
>>> var_3)
>>>
>>> instead of what must be done now, which is:
>>> globals var_1, var_2 \
>>> var_3
>>>
>>
>> The declaration keyword is 'global'; 'globals' is the built-in function.
>> In any case
>>
>> global var_1, var_2
>> global var_3
>>
>> works fine.  There is no connection between the names and, unlike with
>> import, no operational efficiency is gained by mashing the statements
>> together.
>>
>> This issue should be rare.  The global statement is only needed when one
>> is rebinding global names within a function*.  If a function rebinds 10
>> different global names, the design should probably be re-examined.
>>
>> * 'global' at class scope seems useless.
>>
>> a = 0
>> class C:
>> a = 1
>>
>> has the same effect as
>> a = 0
>> a = 1
>> class C: pass
>>
>>
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Re: [Python-ideas] globals should accept parenteses for extending beyond 1 line

2017-01-23 Thread João Matos

Hello,

You are correct, my mistake. I should have written global and not globals.

The purpose of using parentheses on the import statement is not (in my 
view) for operational efficiency but for appearance/cleaness.

The same applies to using it to global.

One does not need to have 10 global vars. It may have to do with var 
name length and the 79 max line length.


This is an example from my one of my programs:
global existing_graph, expected_duration_in_sec, file_size, \
file_mtime, no_change_counter

Anyway, the use of global being rare is of no concern. The point of my 
suggestion is standardization.
My opinion is that a standard language is easier to learn (and teach) 
than one that has different syntax for the same issue, depending on the 
statement.


In short, if the recommended multi-line use for import is

import (a, b,
c)

instead of

import a, b, \
c

Then the same should apply to global.


Best regards,

JM




On 23-01-2017 19:25, Terry Reedy wrote:

On 1/23/2017 1:43 PM, João Matos wrote:

Hello,

I would like to suggest that globals should follow the existing rule
(followed by the import statement, the if statement and in other places)
for extending beyond 1 line using parentheses.
Like this:
globals (var_1, var_2,
var_3)

instead of what must be done now, which is:
globals var_1, var_2 \
var_3


The declaration keyword is 'global'; 'globals' is the built-in 
function.  In any case


global var_1, var_2
global var_3

works fine.  There is no connection between the names and, unlike with 
import, no operational efficiency is gained by mashing the statements 
together.


This issue should be rare.  The global statement is only needed when 
one is rebinding global names within a function*.  If a function 
rebinds 10 different global names, the design should probably be 
re-examined.


* 'global' at class scope seems useless.

a = 0
class C:
a = 1

has the same effect as
a = 0
a = 1
class C: pass



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

Re: [Python-ideas] globals should accept parenteses for extending beyond 1 line

2017-01-23 Thread Terry Reedy

On 1/23/2017 1:43 PM, João Matos wrote:

Hello,

I would like to suggest that globals should follow the existing rule
(followed by the import statement, the if statement and in other places)
for extending beyond 1 line using parentheses.
Like this:
globals (var_1, var_2,
var_3)

instead of what must be done now, which is:
globals var_1, var_2 \
var_3


The declaration keyword is 'global'; 'globals' is the built-in function. 
 In any case


global var_1, var_2
global var_3

works fine.  There is no connection between the names and, unlike with 
import, no operational efficiency is gained by mashing the statements 
together.


This issue should be rare.  The global statement is only needed when one 
is rebinding global names within a function*.  If a function rebinds 10 
different global names, the design should probably be re-examined.


* 'global' at class scope seems useless.

a = 0
class C:
a = 1

has the same effect as
a = 0
a = 1
class C: pass

--
Terry Jan Reedy


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

Re: [Python-ideas] globals should accept parenteses for extending beyond 1 line

2017-01-23 Thread Guido van Rossum
You can just write
  global foo, bar
  global baz, bletch

On Mon, Jan 23, 2017 at 10:43 AM, João Matos  wrote:

> Hello,
>
> I would like to suggest that globals should follow the existing rule
> (followed by the import statement, the if statement and in other places)
> for extending beyond 1 line using parentheses.
> Like this:
> globals (var_1, var_2,
> var_3)
>
> instead of what must be done now, which is:
> globals var_1, var_2 \
> var_3
>
>
> Best regards,
>
> JM
>
>
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>



-- 
--Guido van Rossum (python.org/~guido)
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Alexandre Brault


On 2017-01-23 12:54 PM, Soni L. wrote:
> On 23/01/17 02:56 PM, Gerald Britton wrote:
>> On Jan 23, 2017 11:07 AM, "Soni L." > > wrote:
>>
>> On 23/01/17 01:52 PM, Gerald Britton wrote:
>>>
>>> [snip]
>>>
>>>  
>>>
>>> >I propose `x .= y` -> `x = x . y`, for any `y`.
>>>
>>>  
>>>
>>> [snip]
>>>
>>>  
>>>
>>> I think you mean "any y that is a member of x"
>>>
>>
>> Since it desugars into `x = x.y`, you can literally use anything
>> for `y`.
>>
>> x .= __call__().whatever().unwrap() * 3
>>
>> is equivalent to
>>
>> x = x.__call__().whatever().unwrap() * 3
>>
>> and
>>
>> x .= 1
>>
>> is equivalent to
>>
>> x = x.1
>>
>> which is equivalent to
>>
>> SyntaxError: invalid syntax
>>
>>
>>>  
>>>
>>> Also, note that this syntax means that x will be rebound to
>>> the result of calling x.y, whatever that is (frequently,
>>> None, for mutating methods)
>>>
>>> In general, you can't count on methods to return references
>>> to their instances, even though it's handy for fluent
>>> coding, so this side effect may be unexpected to some
>>>
>>
>> This is why it's for use with **immutable** objects.
>>
>>
>>>  
>>>
>>> That's a problem with your original example:
>>>
>>>  
>>>
>>> >long_name = mkbuilder()
>>>
>>> >long_name = long_name.seta(a)
>>>
>>> >long_name = long_name.setb(b)
>>>
>>> >y = long_name.build()
>>>
>>>  
>>>
>>> What do the methods seta and setb return?  If they don't
>>> return "self" you've got a problem. I think.
>>>
>>
>> They don't return self. Ever. The value bound to long_name is
>> immutable, like an integer. They return a new instance.
>>
>>
>> Then long_name isn't immutable. It changes with every line. That can
>> lead to nasty bugs if you count on its immutability.
>>
>> Easy to see. Just print long_name after each call.
>
> You're mixing up value immutability with name immutability. The name
> isn't immutable, but:
>
> long_name = mkbuilder()
> x = long_name
> long_name .= seta("a")
> y = long_name
> long_name .= setb("b")
> z = long_name
> print(x)  # a = None, b = None
> print(y)  # a = "a", b = None
> print(z)  # a = "a", b = "b"
> print(x is y)  # False
> print(x is z)  # False
> print(y is z)  # False
> print(long_name is z)  # True
This is a really contrived example that doesn't need a special syntax.
Consider instead:

>>> x = mkbuilder()
>>> y = x.seta('a')
>>> z = y.setb('b')
>>> long_name = z

All your prints work as well, this is much easier to mentally parse
(notwithstanding the unpythonesque builder pattern) and doesn't require
the addition of a new syntax that people more knowledgeable than me have
already explained is not a good idea

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

Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Soni L.



On 23/01/17 02:56 PM, Gerald Britton wrote:



On Jan 23, 2017 11:07 AM, "Soni L." > wrote:




On 23/01/17 01:52 PM, Gerald Britton wrote:




[snip]

>I propose `x .= y` -> `x = x . y`, for any `y`.

[snip]

I think you mean "any y that is a member of x"



Since it desugars into `x = x.y`, you can literally use anything
for `y`.

x .= __call__().whatever().unwrap() * 3

is equivalent to

x = x.__call__().whatever().unwrap() * 3

and

x .= 1

is equivalent to

x = x.1

which is equivalent to

SyntaxError: invalid syntax



Also, note that this syntax means that x will be rebound to
the result of calling x.y, whatever that is (frequently,
None, for mutating methods)

In general, you can't count on methods to return references
to their instances, even though it's handy for fluent coding,
so this side effect may be unexpected to some



This is why it's for use with **immutable** objects.



That's a problem with your original example:

>long_name = mkbuilder()

>long_name = long_name.seta(a)

>long_name = long_name.setb(b)

>y = long_name.build()

What do the methods seta and setb return?  If they don't
return "self" you've got a problem. I think.



They don't return self. Ever. The value bound to long_name is
immutable, like an integer. They return a new instance.


Then long_name isn't immutable. It changes with every line. That can 
lead to nasty bugs if you count on its immutability.


Easy to see. Just print long_name after each call.


You're mixing up value immutability with name immutability. The name 
isn't immutable, but:


long_name = mkbuilder()
x = long_name
long_name .= seta("a")
y = long_name
long_name .= setb("b")
z = long_name
print(x)  # a = None, b = None
print(y)  # a = "a", b = None
print(z)  # a = "a", b = "b"
print(x is y)  # False
print(x is z)  # False
print(y is z)  # False
print(long_name is z)  # True

See also:

long_name = 1
x = long_name
long_name += 1
y = long_name
long_name += 1
z = long_name
print(x)  # 1
print(y)  # 2
print(z)  # 3
print(x is y)  # False
print(x is z)  # False
print(y is z)  # False
print(long_name is z)  # True





FWIW why can't you just write:

x.y

or for your example:

long_name.seta(a)

?




See the IRC bot builder example, it should be more clear. (It's
about forking the builder.)




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

Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Gerald Britton
On Jan 23, 2017 11:07 AM, "Soni L."  wrote:



On 23/01/17 01:52 PM, Gerald Britton wrote:




[snip]



>I propose `x .= y` -> `x = x . y`, for any `y`.



[snip]



I think you mean "any y that is a member of x"


Since it desugars into `x = x.y`, you can literally use anything for `y`.

x .= __call__().whatever().unwrap() * 3

is equivalent to

x = x.__call__().whatever().unwrap() * 3

and

x .= 1

is equivalent to

x = x.1

which is equivalent to

SyntaxError: invalid syntax




Also, note that this syntax means that x will be rebound to the result of
calling x.y, whatever that is (frequently, None, for mutating methods)

In general, you can't count on methods to return references to their
instances, even though it's handy for fluent coding, so this side effect
may be unexpected to some


This is why it's for use with **immutable** objects.




That's a problem with your original example:



>long_name = mkbuilder()

>long_name = long_name.seta(a)

>long_name = long_name.setb(b)

>y = long_name.build()



What do the methods seta and setb return?  If they don't return "self"
you've got a problem. I think.


They don't return self. Ever. The value bound to long_name is immutable,
like an integer. They return a new instance.


Then long_name isn't immutable. It changes with every line. That can lead
to nasty bugs if you count on its immutability.

Easy to see. Just print long_name after each call.





FWIW why can't you just write:



x.y



or for your example:



long_name.seta(a)



?



See the IRC bot builder example, it should be more clear. (It's about
forking the builder.)
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Guido van Rossum
On Mon, Jan 23, 2017 at 8:07 AM, Soni L.  wrote:

>
>
> Since it desugars into `x = x.y`, you can literally use anything for `y`.
>
> x .= __call__().whatever().unwrap() * 3
>
> is equivalent to
>
> x = x.__call__().whatever().unwrap() * 3
>
> and
>
> x .= 1
>
> is equivalent to
>
> x = x.1
>
> which is equivalent to
>
> SyntaxError: invalid syntax
>

And that's exactly the problem. Users would be greatly confused because
what's to the right of `.=` is *not* an expression, it's something more
restricted (in particular it must start with a plain identifier). This
makes the `.=` operator a very different beast from `=`, `+=` and friends.

I assume you think that's fine, but given your cavalier attitude about `x
.= 1` my feeling is that you don't have a lot of experience designing and
implementing language features. That is okay, you are learning it here. But
perhaps you should take the hint from the large number of people here who
have gently tried to explain to you that while this is a good idea, it's
not a great idea, and there's no sufficiently important use case to make up
for the confusion (indicated above) that it will inevitably cause.

-- 
--Guido van Rossum (python.org/~guido)
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Soni L.



On 23/01/17 01:52 PM, Gerald Britton wrote:




[snip]

>I propose `x .= y` -> `x = x . y`, for any `y`.

[snip]

I think you mean "any y that is a member of x"



Since it desugars into `x = x.y`, you can literally use anything for `y`.

x .= __call__().whatever().unwrap() * 3

is equivalent to

x = x.__call__().whatever().unwrap() * 3

and

x .= 1

is equivalent to

x = x.1

which is equivalent to

SyntaxError: invalid syntax


Also, note that this syntax means that x will be rebound to the
result of calling x.y, whatever that is (frequently, None, for
mutating methods)

In general, you can't count on methods to return references to
their instances, even though it's handy for fluent coding, so this
side effect may be unexpected to some



This is why it's for use with **immutable** objects.


That's a problem with your original example:

>long_name = mkbuilder()

>long_name = long_name.seta(a)

>long_name = long_name.setb(b)

>y = long_name.build()

What do the methods seta and setb return?  If they don't return
"self" you've got a problem. I think.



They don't return self. Ever. The value bound to long_name is immutable, 
like an integer. They return a new instance.



FWIW why can't you just write:

x.y

or for your example:

long_name.seta(a)

?




See the IRC bot builder example, it should be more clear. (It's about 
forking the builder.)
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Ethan Furman

On 01/23/2017 05:33 AM, Soni L. wrote:


It's literally sugar for repeating the name and moving the dot to the right.
 I think it's clearer than most other compound operators in that it doesn't
 affect precedence rules.

`x += y`, for any code `y`, is equivalent to `x = x + (y)`, not `x = x + y`.

`x .= y`, for any code `y`, is equivalent to `x = x . y`, not `x = x . (y)`.


This is not an improvement.

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


[Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Gerald Britton
[snip]



>I propose `x .= y` -> `x = x . y`, for any `y`.



[snip]



I think you mean "any y that is a member of x"



Also, note that this syntax means that x will be rebound to the result of
calling x.y, whatever that is (frequently, None, for mutating methods)

In general, you can't count on methods to return references to their
instances, even though it's handy for fluent coding, so this side effect
may be unexpected to some



That's a problem with your original example:



>long_name = mkbuilder()

>long_name = long_name.seta(a)

>long_name = long_name.setb(b)

>y = long_name.build()



What do the methods seta and setb return?  If they don't return "self"
you've got a problem. I think.



FWIW why can't you just write:



x.y



or for your example:



long_name.seta(a)



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

Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Wes Turner
On Sunday, January 22, 2017, Wes Turner  wrote:

>
>
> On Sunday, January 22, 2017, Soni L.  > wrote:
>
>>
>>
>> On 22/01/17 10:03 PM, Wes Turner wrote:
>>
>>
>>
>> On Sunday, January 22, 2017, Wes Turner  wrote:
>>
>>> Have you looked at pyrsistent for 
>>> immutable/functional/persistent/copy-on-write
>>> data structures in Python?
>>>
>>> https://github.com/tobgu/pyrsistent/
>>>
>>> (freeze() / thaw())
>>>
>>> ... e.g. List and Dict NamedTuple values are not immutable (because
>>> append() and update() still work)
>>>
>>
>> fn.py also has immutables:
>> https://github.com/kachayev/fn.py/blob/master/README.rst#per
>> sistent-data-structures
>>
>>
>> You seem to be thinking of "immutable object builder". Not "the builder
>> itself is immutable and operations on it create new builders".
>>
>
> My mistake.
> Something like @optionable and/or @curried from fn.py in conjunction with
> PClass from pyrsistent may accomplish what you describe?
>

From
http://pyrsistent.readthedocs.io/en/latest/api.html#pyrsistent.PClass.set :

"Set a field in the instance. Returns a new instance with the updated
value. The original instance remains unmodified. Accepts key-value pairs or
single string representing the field name and a value."




>
>>
>>
>>
>>
>>>
>>> On Sunday, January 22, 2017, Soni L.  wrote:
>>>
 I've been thinking of an Immutable Builder pattern and an operator to
 go with it. Since the builder would be immutable, this wouldn't work:

 long_name = mkbuilder()
 long_name.seta(a)
 long_name.setb(b)
 y = long_name.build()

 Instead, you'd need something more like this:

 long_name = mkbuilder()
 long_name = long_name.seta(a)
 long_name = long_name.setb(b)
 y = long_name.build()

 Or we could add an operator to simplify it:

 long_name = mkbuilder()
 long_name .= seta(a)
 long_name .= setb(b)
 y = long_name.build()

 (Yes, I'm aware you can x = mkbuilder().seta(a).setb(b), then y =
 x.build(). But that doesn't work if you wanna "fork" the builder. Some
 builders, like a builder for network connections of some sort, would work
 best if they were immutable/forkable.)
 ___
 Python-ideas mailing list
 Python-ideas@python.org
 https://mail.python.org/mailman/listinfo/python-ideas
 Code of Conduct: http://python.org/psf/codeofconduct/

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

Re: [Python-ideas] Immutable Builder" Pattern and Operator

2017-01-23 Thread Paul Moore
On 23 January 2017 at 13:47, Hervé "Kyle" MUTOMBO
 wrote:
> Paul Moore is clearly right when He says that this "a .= 1+1" doesn't make
> sense. It means nothing understandable although in "a .= s(e)" can mean
> something. As a matter of fact "a .= EXPR" is bound to succeed only in a
> very small set of cases.

By responding to a digest you make it very hard to see what you're
replying to. Could you get the messages as individual ones, and reply
quoting the context properly, please?

I'm not sure how to interpret your above comment in the light of your
other comment

> Pleasing to see and somehow elegant. I believe .= is a good idea.

as I'm arguing pretty strongly that .= is *not* a good idea, because
there are all sorts of ill-defined cases that haven't been clearly
explained in a way that matches the rest of Python's grammar and
semantics.

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

Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Random832
On Mon, Jan 23, 2017, at 09:12, Soni L. wrote:
> Builders for network connections where you don't wanna start with a 
> fresh builder every time.

Maybe you need a builder builder.

Or, more seriously, a way to differentiate the things in the 'builder'
from the things that are going to be different with each connection, and
pass them separately in the connection's constructor.

Or a clone method.

> It is far more useful only because it's not just a syntax sugar. It's 
> more like a completely new, standalone operator.
> Which, IMO, makes it more confusing.
> 
> I propose `x .= y` -> `x = x . y`, for any `y`.

I think you're underestimating the extent to which the fact that "y"
isn't a real expression will cause confusion.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Soni L.



On 23/01/17 11:54 AM, Steven D'Aprano wrote:

On Mon, Jan 23, 2017 at 12:49:19AM -0200, Soni L. wrote:
[...]

You seem to be thinking of "immutable object builder". Not "the builder
itself is immutable and operations on it create new builders".

Why would you make a builder class immutable?


Builders for network connections where you don't wanna start with a 
fresh builder every time.




That's not a rhetorical question -- I'm genuinely surprised that you're
not only using the builder design pattern (there are usually better
solutions in Python) but more so that you're making the builder itself
immutable.

In any case, it seems that this is such a narrow and unusual use-case
that it wouldn't be wise to give it special syntax. Especially when
there are other, potentially far more useful, uses for the .= syntax,
e.g. Julia's syntactic loop fusion:

http://julialang.org/blog/2017/01/moredots



It is far more useful only because it's not just a syntax sugar. It's 
more like a completely new, standalone operator.

Which, IMO, makes it more confusing.

I propose `x .= y` -> `x = x . y`, for any `y`.
You propose `x .= y` -> `operate_on(x).with(lambda: y)`

This feels like you're arguing for loops are more useful than 
multiplication, and thus we shouldn't have multiplication.





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


Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Steven D'Aprano
On Mon, Jan 23, 2017 at 12:49:19AM -0200, Soni L. wrote:
[...]
> You seem to be thinking of "immutable object builder". Not "the builder 
> itself is immutable and operations on it create new builders".

Why would you make a builder class immutable?

That's not a rhetorical question -- I'm genuinely surprised that you're 
not only using the builder design pattern (there are usually better 
solutions in Python) but more so that you're making the builder itself 
immutable.

In any case, it seems that this is such a narrow and unusual use-case 
that it wouldn't be wise to give it special syntax. Especially when 
there are other, potentially far more useful, uses for the .= syntax, 
e.g. Julia's syntactic loop fusion:

http://julialang.org/blog/2017/01/moredots




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


Re: [Python-ideas] Immutable Builder" Pattern and Operator

2017-01-23 Thread Kyle
Paul Moore is clearly right when He says that this "a .= 1+1" doesn't make
sense. It means nothing understandable although in "a .= s(e)" can mean
something. As a matter of fact "a .= EXPR" is bound to succeed only in a
very small set of cases.
On Jan 23, 2017 14:39,  wrote:

Send Python-ideas mailing list submissions to
python-ideas@python.org

To subscribe or unsubscribe via the World Wide Web, visit
https://mail.python.org/mailman/listinfo/python-ideas
or, via email, send a message with subject or body 'help' to
python-ideas-requ...@python.org

You can reach the person managing the list at
python-ideas-ow...@python.org

When replying, please edit your Subject line so it is more specific
than "Re: Contents of Python-ideas digest..."


Today's Topics:

   1. Re: "Immutable Builder" Pattern and Operator (Paul Moore)
   2. Re: "Immutable Builder" Pattern and Operator (Soni L.)
   3. Re: Python-ideas Digest, Vol 122, Issue 81 (Herv? Kyle MUTOMBO)


--

Message: 1
Date: Mon, 23 Jan 2017 13:26:49 +
From: Paul Moore 
To: "Soni L." 
Cc: Python-Ideas 
Subject: Re: [Python-ideas] "Immutable Builder" Pattern and Operator
Message-ID:

Re: [Python-ideas] Python-ideas Digest, Vol 122, Issue 81

2017-01-23 Thread Kyle
Pleasing to see and somehow elegant. I believe .= is a good idea.
On Jan 23, 2017 14:18, <python-ideas-requ...@python.org> wrote:

> Send Python-ideas mailing list submissions to
> python-ideas@python.org
>
> To subscribe or unsubscribe via the World Wide Web, visit
> https://mail.python.org/mailman/listinfo/python-ideas
> or, via email, send a message with subject or body 'help' to
> python-ideas-requ...@python.org
>
> You can reach the person managing the list at
> python-ideas-ow...@python.org
>
> When replying, please edit your Subject line so it is more specific
> than "Re: Contents of Python-ideas digest..."
>
>
> Today's Topics:
>
>1. Re: "Immutable Builder" Pattern and Operator (Cory Benfield)
>2. Re: "Immutable Builder" Pattern and Operator (Paul Moore)
>3. Re: "Immutable Builder" Pattern and Operator (Serhiy Storchaka)
>4. Re: "Immutable Builder" Pattern and Operator (Soni L.)
>5. Re: "Immutable Builder" Pattern and Operator (M.-A. Lemburg)
>
>
> --
>
> Message: 1
> Date: Mon, 23 Jan 2017 09:32:02 +
> From: Cory Benfield <c...@lukasa.co.uk>
> To: "Soni L." <fakedme...@gmail.com>
> Cc: python-ideas@python.org
> Subject: Re: [Python-ideas] "Immutable Builder" Pattern and Operator
> Message-ID: <8671ebca-148f-41c8-a592-46ef653b9...@lukasa.co.uk>
> Content-Type: text/plain; charset="utf-8"
>
>
> > On 22 Jan 2017, at 22:45, Soni L. <fakedme...@gmail.com> wrote:
> >
> >
>
> This pattern is present in the cryptography module already with things
> like their x509.CertificateBuilder: https://cryptography.io/en/
> latest/x509/reference/#cryptography.x509.CertificateBuilder <
> https://cryptography.io/en/latest/x509/reference/#cryptography.x509.
> CertificateBuilder>.
>
> My 2c, but I find that code perfectly readable and legible. I don?t think
> a dot-equals operator would be needed.
>
> Cory
> -- next part --
> An HTML attachment was scrubbed...
> URL: <http://mail.python.org/pipermail/python-ideas/
> attachments/20170123/c4e7d09f/attachment-0001.html>
>
> --
>
> Message: 2
> Date: Mon, 23 Jan 2017 09:54:55 +
> From: Paul Moore <p.f.mo...@gmail.com>
> To: "Soni L." <fakedme...@gmail.com>
> Cc: Python-Ideas <python-ideas@python.org>
> Subject: Re: [Python-ideas] "Immutable Builder" Pattern and Operator
> Message-ID:
> <CACac1F9CcDEyNuvGBSNSpm+U0=VQNaN9Yd-Mgj+q_Uk16gxGfQ@mail.
> gmail.com>
> Content-Type: text/plain; charset=UTF-8
>
> On 22 January 2017 at 22:45, Soni L. <fakedme...@gmail.com> wrote:
> > I've been thinking of an Immutable Builder pattern and an operator to go
> > with it. Since the builder would be immutable, this wouldn't work:
> >
> > long_name = mkbuilder()
> > long_name.seta(a)
> > long_name.setb(b)
> > y = long_name.build()
> >
> > Instead, you'd need something more like this:
> >
> > long_name = mkbuilder()
> > long_name = long_name.seta(a)
> > long_name = long_name.setb(b)
> > y = long_name.build()
> >
> > Or we could add an operator to simplify it:
> >
> > long_name = mkbuilder()
> > long_name .= seta(a)
> > long_name .= setb(b)
> > y = long_name.build()
> >
> > (Yes, I'm aware you can x = mkbuilder().seta(a).setb(b), then y =
> x.build().
> > But that doesn't work if you wanna "fork" the builder. Some builders,
> like a
> > builder for network connections of some sort, would work best if they
> were
> > immutable/forkable.)
>
> I don't think the .= operator adds enough to be worth it. If the
> problem you see is the duplication of long_name in those lines (it's
> difficult to be sure without a real example) then you can use a
> temporary:
>
> b = mkbuilder()
> b = b.seta(a)
> b = b.setb(b)
> long_name = b
> y = long_name.build()
>
> For your real example:
>
> On 22 January 2017 at 23:30, Soni L. <fakedme...@gmail.com> wrote:
> > fnircbotbuilder = mkircbotbuilder(network="irc.freenode.net", port=6697,
> > ssl=true)
> > mainbot = mkircbotbuilder(parent=fnircbotbuilder,  # ???
> >   channels=["#bots"]).build()
> > fndccbotbuilder = mkircbotbuilder(parent=fnircbotbuilder, dcc=true,
> > channeldcc=true)
> > dccbot = mkircbotbuilder(parent=fndccbotbuilder,
> > channels=["#ct

Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread M.-A. Lemburg
On 23.01.2017 14:05, Soni L. wrote:
> 
> 
> On 23/01/17 09:45 AM, Serhiy Storchaka wrote:
>> On 23.01.17 01:30, Soni L. wrote:
>>> On 22/01/17 08:54 PM, Serhiy Storchaka wrote:
 On 23.01.17 00:45, Soni L. wrote:
> I've been thinking of an Immutable Builder pattern and an operator
> to go
> with it. Since the builder would be immutable, this wouldn't work:
>
> long_name = mkbuilder()
> long_name.seta(a)
> long_name.setb(b)
> y = long_name.build()

 I think the more pythonic way is:

 y = build(a=a, b=b)

 A Builder pattern is less used in Python due to the support of keyword
 arguments.
>>>
>>> I guess you could do something like this, for an IRC bot builder:
>>>
>>> fnircbotbuilder = mkircbotbuilder(network="irc.freenode.net", port=6697,
>>> ssl=true)
>>> mainbot = mkircbotbuilder(parent=fnircbotbuilder,  # ???
>>>   channels=["#bots"]).build()
>>> fndccbotbuilder = mkircbotbuilder(parent=fnircbotbuilder, dcc=true,
>>> channeldcc=true)
>>> dccbot = mkircbotbuilder(parent=fndccbotbuilder,
>>> channels=["#ctcp-s"]).build()
>>> otherircbotbuilder = mkircbotbuilder(parent=fndccbotbuilder,
>>> network="irc.subluminal.net")  # because we want this whole network
>>> otherbot = mkircbotbuilder(parent=otherircbotbuilder,
>>> channels=["#programming"]).build()# to use DCC and channel DCC
>>>
>>> But this would be cleaner:
>>>
>>> botbuilder =
>>> mkircbotbuilder().network("irc.freenode.net").port(6697).ssl(true)
>>> mainbot = botbuilder.channels(["#bots"]).build()
>>> botbuilder .= dcc(true).channeldcc(true)
>>> dccbot = botbuilder.channels(["#ctcp-s"]).build()
>>> botbuilder .= network("irc.subluminal.net")
>>> otherbot = botbuilder.channels(["#programming"]).build()
>>
>> In Python you can save common options in a dict and pass them as
>> var-keyword argument. Or use functools.partial. In any case you don't
>> need a builder class with the build method and a number of configuring
>> methods. It can be just a function with optional keyword parameters.
>>
>> A Builder pattern is often used in languages that don't support
>> passing arguments by keyword and partial functions. Python rarely
>> needs the purposed class implementing a Builder pattern. Actually a
>> Builder pattern is built-in in the language as a part of syntax.
>>
> Yeah but the dotequals operator has many other benefits:
> 
> long_name .= __call__  # cast to callable
> long_name .= wrapped  # unwrap
> etc
> 
> And it also looks neat.

I don't see this an being a particular intuitive way of writing
such rather uncommon constructs.

The syntax is not clear (what if you have an expression on the RHS)
and it doesn't save you much in writing (if long_name is too long
simply rebind it under a shorter name for the purpose of the code
block).

Also note that rebinding different objects to the same name
in the same block is often poor style and can easily lead to
hard to track bugs.

-- 
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Experts (#1, Jan 23 2017)
>>> Python Projects, Coaching and Consulting ...  http://www.egenix.com/
>>> Python Database Interfaces ...   http://products.egenix.com/
>>> Plone/Zope Database Interfaces ...   http://zope.egenix.com/


::: We implement business ideas - efficiently in both time and costs :::

   eGenix.com Software, Skills and Services GmbH  Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
   Registered at Amtsgericht Duesseldorf: HRB 46611
   http://www.egenix.com/company/contact/
  http://www.malemburg.com/

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


Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Soni L.



On 23/01/17 09:45 AM, Serhiy Storchaka wrote:

On 23.01.17 01:30, Soni L. wrote:

On 22/01/17 08:54 PM, Serhiy Storchaka wrote:

On 23.01.17 00:45, Soni L. wrote:
I've been thinking of an Immutable Builder pattern and an operator 
to go

with it. Since the builder would be immutable, this wouldn't work:

long_name = mkbuilder()
long_name.seta(a)
long_name.setb(b)
y = long_name.build()


I think the more pythonic way is:

y = build(a=a, b=b)

A Builder pattern is less used in Python due to the support of keyword
arguments.


I guess you could do something like this, for an IRC bot builder:

fnircbotbuilder = mkircbotbuilder(network="irc.freenode.net", port=6697,
ssl=true)
mainbot = mkircbotbuilder(parent=fnircbotbuilder,  # ???
  channels=["#bots"]).build()
fndccbotbuilder = mkircbotbuilder(parent=fnircbotbuilder, dcc=true,
channeldcc=true)
dccbot = mkircbotbuilder(parent=fndccbotbuilder,
channels=["#ctcp-s"]).build()
otherircbotbuilder = mkircbotbuilder(parent=fndccbotbuilder,
network="irc.subluminal.net")  # because we want this whole network
otherbot = mkircbotbuilder(parent=otherircbotbuilder,
channels=["#programming"]).build()# to use DCC and channel DCC

But this would be cleaner:

botbuilder =
mkircbotbuilder().network("irc.freenode.net").port(6697).ssl(true)
mainbot = botbuilder.channels(["#bots"]).build()
botbuilder .= dcc(true).channeldcc(true)
dccbot = botbuilder.channels(["#ctcp-s"]).build()
botbuilder .= network("irc.subluminal.net")
otherbot = botbuilder.channels(["#programming"]).build()


In Python you can save common options in a dict and pass them as 
var-keyword argument. Or use functools.partial. In any case you don't 
need a builder class with the build method and a number of configuring 
methods. It can be just a function with optional keyword parameters.


A Builder pattern is often used in languages that don't support 
passing arguments by keyword and partial functions. Python rarely 
needs the purposed class implementing a Builder pattern. Actually a 
Builder pattern is built-in in the language as a part of syntax.



Yeah but the dotequals operator has many other benefits:

long_name .= __call__  # cast to callable
long_name .= wrapped  # unwrap
etc

And it also looks neat.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Serhiy Storchaka

On 23.01.17 01:30, Soni L. wrote:

On 22/01/17 08:54 PM, Serhiy Storchaka wrote:

On 23.01.17 00:45, Soni L. wrote:

I've been thinking of an Immutable Builder pattern and an operator to go
with it. Since the builder would be immutable, this wouldn't work:

long_name = mkbuilder()
long_name.seta(a)
long_name.setb(b)
y = long_name.build()


I think the more pythonic way is:

y = build(a=a, b=b)

A Builder pattern is less used in Python due to the support of keyword
arguments.


I guess you could do something like this, for an IRC bot builder:

fnircbotbuilder = mkircbotbuilder(network="irc.freenode.net", port=6697,
ssl=true)
mainbot = mkircbotbuilder(parent=fnircbotbuilder,  # ???
  channels=["#bots"]).build()
fndccbotbuilder = mkircbotbuilder(parent=fnircbotbuilder, dcc=true,
channeldcc=true)
dccbot = mkircbotbuilder(parent=fndccbotbuilder,
channels=["#ctcp-s"]).build()
otherircbotbuilder = mkircbotbuilder(parent=fndccbotbuilder,
network="irc.subluminal.net")  # because we want this whole network
otherbot = mkircbotbuilder(parent=otherircbotbuilder,
channels=["#programming"]).build()# to use DCC and channel DCC

But this would be cleaner:

botbuilder =
mkircbotbuilder().network("irc.freenode.net").port(6697).ssl(true)
mainbot = botbuilder.channels(["#bots"]).build()
botbuilder .= dcc(true).channeldcc(true)
dccbot = botbuilder.channels(["#ctcp-s"]).build()
botbuilder .= network("irc.subluminal.net")
otherbot = botbuilder.channels(["#programming"]).build()


In Python you can save common options in a dict and pass them as 
var-keyword argument. Or use functools.partial. In any case you don't 
need a builder class with the build method and a number of configuring 
methods. It can be just a function with optional keyword parameters.


A Builder pattern is often used in languages that don't support passing 
arguments by keyword and partial functions. Python rarely needs the 
purposed class implementing a Builder pattern. Actually a Builder 
pattern is built-in in the language as a part of syntax.



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


Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Paul Moore
On 22 January 2017 at 22:45, Soni L.  wrote:
> I've been thinking of an Immutable Builder pattern and an operator to go
> with it. Since the builder would be immutable, this wouldn't work:
>
> long_name = mkbuilder()
> long_name.seta(a)
> long_name.setb(b)
> y = long_name.build()
>
> Instead, you'd need something more like this:
>
> long_name = mkbuilder()
> long_name = long_name.seta(a)
> long_name = long_name.setb(b)
> y = long_name.build()
>
> Or we could add an operator to simplify it:
>
> long_name = mkbuilder()
> long_name .= seta(a)
> long_name .= setb(b)
> y = long_name.build()
>
> (Yes, I'm aware you can x = mkbuilder().seta(a).setb(b), then y = x.build().
> But that doesn't work if you wanna "fork" the builder. Some builders, like a
> builder for network connections of some sort, would work best if they were
> immutable/forkable.)

I don't think the .= operator adds enough to be worth it. If the
problem you see is the duplication of long_name in those lines (it's
difficult to be sure without a real example) then you can use a
temporary:

b = mkbuilder()
b = b.seta(a)
b = b.setb(b)
long_name = b
y = long_name.build()

For your real example:

On 22 January 2017 at 23:30, Soni L.  wrote:
> fnircbotbuilder = mkircbotbuilder(network="irc.freenode.net", port=6697,
> ssl=true)
> mainbot = mkircbotbuilder(parent=fnircbotbuilder,  # ???
>   channels=["#bots"]).build()
> fndccbotbuilder = mkircbotbuilder(parent=fnircbotbuilder, dcc=true,
> channeldcc=true)
> dccbot = mkircbotbuilder(parent=fndccbotbuilder,
> channels=["#ctcp-s"]).build()
> otherircbotbuilder = mkircbotbuilder(parent=fndccbotbuilder,
> network="irc.subluminal.net")  # because we want this whole network
> otherbot = mkircbotbuilder(parent=otherircbotbuilder,
> channels=["#programming"]).build()# to use DCC and channel DCC
>
> But this would be cleaner:
>
> botbuilder =
> mkircbotbuilder().network("irc.freenode.net").port(6697).ssl(true)
> mainbot = botbuilder.channels(["#bots"]).build()
> botbuilder .= dcc(true).channeldcc(true)
> dccbot = botbuilder.channels(["#ctcp-s"]).build()
> botbuilder .= network("irc.subluminal.net")
> otherbot = botbuilder.channels(["#programming"]).build()

I don't find the second example appreciably cleaner than the first.
But a bit of reformatting looks better to me:

# First create builders for the bots
fnircbotbuilder = mkircbotbuilder(
network="irc.freenode.net",
port=6697,
ssl=true)
fndccbotbuilder = mkircbotbuilder(
parent=fnircbotbuilder,
dcc=true,
channeldcc=true)
otherircbotbuilder = mkircbotbuilder(
parent=fndccbotbuilder,
network="irc.subluminal.net")

# Now create the actual bots
mainbot = mkircbotbuilder(
parent=fnircbotbuilder,
channels=["#bots"]).build()
dccbot = mkircbotbuilder(
parent=fndccbotbuilder,
channels=["#ctcp-s"]).build()
otherbot = mkircbotbuilder(
parent=otherircbotbuilder,
channels=["#programming"]).build()

And some API redesign (make the builders classes, and the parent
relationship becomes subclassing, and maybe make channels an argument
to build() so that you don't need fresh builders for each of the
actual bots, and you don't even need the "builder" in the name at this
point) makes the whole thing look far cleaner (to me, at least):

class FNIRCBot(IRCBot):
network="irc.freenode.net"
port=6697
ssl=True
class FNDCCBot(FNIRCBot):
dcc=True
channeldcc=True
class OtherIRCBot(IRCBot):
network="irc.subluminal.net"

mainbot = FNIRCBot(channels=["#bots"])
dccbot = FNDCCBot(channels=["#ctcp-s"])
otherbot = OtherIRCBot(channels=["#programming"])

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


Re: [Python-ideas] "Immutable Builder" Pattern and Operator

2017-01-23 Thread Cory Benfield

> On 22 Jan 2017, at 22:45, Soni L.  wrote:
> 
> 

This pattern is present in the cryptography module already with things like 
their x509.CertificateBuilder: 
https://cryptography.io/en/latest/x509/reference/#cryptography.x509.CertificateBuilder
 
.

My 2c, but I find that code perfectly readable and legible. I don’t think a 
dot-equals operator would be needed.

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