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

On Jan 23, 2017 14:18, <python-ideas-request@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-request@python.org

You can reach the person managing the list at
        python-ideas-owner@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 +0000
From: Cory Benfield <cory@lukasa.co.uk>
To: "Soni L." <fakedme+py@gmail.com>
Cc: python-ideas@python.org
Subject: Re: [Python-ideas] "Immutable Builder" Pattern and Operator
Message-ID: <8671EBCA-148F-41C8-A592-46EF653B9CAE@lukasa.co.uk>
Content-Type: text/plain; charset="utf-8"


> On 22 Jan 2017, at 22:45, Soni L. <fakedme+py@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 +0000
From: Paul Moore <p.f.moore@gmail.com>
To: "Soni L." <fakedme+py@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+py@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+py@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=["#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


------------------------------

Message: 3
Date: Mon, 23 Jan 2017 13:45:18 +0200
From: Serhiy Storchaka <storchaka@gmail.com>
To: python-ideas@python.org
Subject: Re: [Python-ideas] "Immutable Builder" Pattern and Operator
Message-ID: <o64qc9$k3q$1@blaine.gmane.org>
Content-Type: text/plain; charset=windows-1252; format=flowed

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.




------------------------------

Message: 4
Date: Mon, 23 Jan 2017 11:05:12 -0200
From: "Soni L." <fakedme+py@gmail.com>
To: python-ideas@python.org
Subject: Re: [Python-ideas] "Immutable Builder" Pattern and Operator
Message-ID: <e9f1547f-c5a6-045a-8716-7669a1662b32@gmail.com>
Content-Type: text/plain; charset=windows-1252; format=flowed



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.


------------------------------

Message: 5
Date: Mon, 23 Jan 2017 14:18:18 +0100
From: "M.-A. Lemburg" <mal@egenix.com>
To: "Soni L." <fakedme+py@gmail.com>, python-ideas@python.org
Subject: Re: [Python-ideas] "Immutable Builder" Pattern and Operator
Message-ID: <0654a27e-7200-c468-d4eb-17bef13b61d2@egenix.com>
Content-Type: text/plain; charset=windows-1252

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/



------------------------------

Subject: Digest Footer

_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas


------------------------------

End of Python-ideas Digest, Vol 122, Issue 81
*********************************************