Re: [Python-ideas] "old" values in postconditions

2018-09-28 Thread Marko Ristin-Kaufmann
Hi James,
I'm a bit short on time today, and would need some more time and attention
to understand the proposal you wrote. I'll try to come back to you
tomorrow.

In any case, I need to refactor icontract's decorators to use conditions
like lambda P: and lambda P, result: first before adding snapshot
functionality.

What about having @snapshot_with and @snapshot? @Snapshot_with does what
you propose and @snapshot expects a lambda P, identifier: ?

After the refactoring, maybe the same could be done for defining contracts
as well? (Requires and requires_that?)

If the documentation is clear, I'd expect the user to be able to
distinguish the two. The first approach is shorter, and uses magic, but
fails in some rare situations. The other method is more verbose, but always
works.

Cheers,
Marko

Le sam. 29 sept. 2018 à 00:35, James Lu  a écrit :

> I am fine with your proposed syntax. It’s certainly lucid. Perhaps it
> would be a good idea to get people accustomed to “non-magic” syntax.
>
> I still have a feeling that most developers would like to store the state
> in many different custom ways.
>
> Please explain. (Expressions like thunk(all)(a == b for a, b in
> P.arg.meth()) would be valid.)
>
> I'm thinking mostly about all the edge cases which we would not be able to
> cover (and how complex that would be to cover them).
>
>
> Except for a > b > c being one flat expression with 5 members, it seems
> fairly easy to recreate an AST, which can then be compiled down to a code
> object. The code object can be fun with a custom “locals()”
>
> Below is my concept code for such a P object.
>
> from ast import *
>
> # not done: enforce Singleton property on EmptySymbolType
>
> class EmptySymbolType(object): ...
>
> EmptySymbol = EmptySymbolType() # empty symbols are placeholders
>
> class MockP(object):
>
> # "^" is xor
>
> @icontract.pre(lambda symbol, astnode: (symbol is None) ^ (astnode is
> None))
>
> def __init__(self, symbol=None, value=EmptySymbol, astnode=None,
> initsymtable=(,)):
>
> self.symtable = dict(initsymtable)
>
> if symbol:
>
> self.expr = Expr(value=Name(id=symbol, ctx=Load()))
>
> self.symtable = {symbol: value}
>
> else:
>
> self.expr = astnode
>
> self.frozen = False
>
> def __add__(self, other):
>
> wrapped = MockP.wrap_value(other)
>
> return MockP(astnode=Expr(value=BinOp(self.expr, Add(),
> wrapped.expr), initsymtable={**self.symtable, **wrapped.symtable})
>
> def compile(self): ...
>
> def freeze(self):
>
> # frozen objects wouldn’t have an overrided getattr, allowing for
> icontract to manipulate the MockP object using its public interface
>
> self.frozen = True
>
> @classmethod
>
> def wrap_value(cls, obj):
>
># create a MockP object from a value. Generate a random identifier
> and set that as the key in symtable, the AST node is the name of that
> identifier, retrieving its value through simple expression evaluation.
>
>...
>
>
> thunk = MockP.wrap_value
>
> P = MockP('P')
>
> # elsewhere: ensure P is only accessed via valid “dot attribute access”
> inside @snapshot so contracts fail early, or don’t and allow Magic like
> __dict__ to occur on P.
>
> On Sep 27, 2018, at 9:49 PM, Marko Ristin-Kaufmann 
> wrote:
>
> Hi James,
>
> I still have a feeling that most developers would like to store the state
> in many different custom ways. I see also thunk and snapshot with wrapper
> objects to be much more complicated to implement and maintain; I'm thinking
> mostly about all the edge cases which we would not be able to cover (and
> how complex that would be to cover them). Then the linters need also to
> work around such wrappers... It might also scare users off since it looks
> like too much magic. Another concern I also have is that it's probably very
> hard to integrate these wrappers with mypy later -- but I don't really have
> a clue about that, only my gut feeling?
>
> What about we accepted to repeat "lambda P, " prefix, and have something
> like this:
>
> @snapshot(
>   lambda P, some_name: len(P.some_property),
>   lambda P, another_name: hash(P.another_property)
> )
>
> It's not too verbose for me and you can still explain in three-four
> sentences what happens below the hub in the library's docs.  A
> pycharm/pydev/vim/emacs plugins could hide the verbose parts.
>
> I performed a small experiment to test how this solution plays with pylint
> and it seems OK that arguments are not used in lambdas.
>
> Cheers,
> Marko
>
>
> On Thu, 27 Sep 2018 at 12:27, James Lu  wrote:
>
>> Why couldn’t we record the operations  done to a special object and
>> replay them?
>>
>> Actually, I think there is probably no way around a decorator that
>>> captures/snapshots the data before the function call with a lambda (or even
>>> a separate function). "Old" construct, if we are to parse it somehow from
>>> the condition function, would limit us only to 

Re: [Python-ideas] Why is design-by-contracts not widely adopted?

2018-09-28 Thread Steven D'Aprano
On Sat, Sep 29, 2018 at 12:30:45PM +1200, Greg Ewing wrote:
> Chris Angelico wrote:
> >But as a part of the
> >function's declared intent, it's fine to have a postcondition of "the
> >directory will be empty" even though something could drop a file into
> >it.
> 
> If you only intend the contract to serve as documentation,
> I suppose that's okay, but it means you can't turn on runtime
> checking of contracts, otherwise your program could suffer
> spurious failures.

If your code can cope with a particular file system state ("directory 
isn't empty") then you don't need to specify it as a precondition. If it 
can't cope, then it isn't a spurious failure, its a real failure. You 
either get an error when the condition is checked, up front, or you get 
an error in the middle of processing the directory.

Of course for many things (especially file system operations) you need 
to be prepared to handle I/O errors *even if the precondition passed*. 
So what? That hasn't changed, and nobody said that contracts were a cure 
for Time Of Check To Time Of Use bugs.

Contracts are a tool to help developers write better code, not a magic 
wand. You still need to write your code in a way which isn't vulnerable 
to TOCTTOU failures, contracts or not.

Anticipating an objection: why bother with the precondition check if the 
code has to handle an error anyway?

Because it is better to get an upfront error than an error halfway 
through processing. In general you get a better, more informative error 
message, closer to the place where it matters, if you fail fast.

Yes yes yes, in theory you might have a precondition requirement which 
would fail up front but resolve itself before it matters:

directory not empty
start running your program
precondition check fails
... later
directory is emptied by another process
your program actually needs to use the empty directory

but do you really think it is good practice to design your code on the 
basis of that? Better to write your code conservatively: if the 
directory isn't empty up front, don't hope it will empty itself, fail 
fast, but be prepared to handle the error case as well.


-- 
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] "while:" for the loop

2018-09-28 Thread Mikhail V
I put the list of related discussion here, just in case.

Same suggestion:
https://mail.python.org/pipermail/python-dev/2005-July/054914.html

Idea for the "loop" keyword:
https://mail.python.org/pipermail/python-ideas/2014-June/028202.html
(followed by the same suggestion from @Random832:
https://mail.python.org/pipermail/python-ideas/2014-June/028220.html)

Somewhat related PEP (rejected) + discussion links inside:
https://legacy.python.org/dev/peps/pep-0315/
(I've meditated a bit on this - but could not get what was
actually the point of that idea.)

Plus some other related discussions, maybe not directly related,
but something along the lines might be interesting.

An old and lively one:
https://mail.python.org/pipermail/python-list/1999-April/002557.html
https://mail.python.org/pipermail/python-list/1999-May/008535.html
Another one:
https://mail.python.org/pipermail/python-list/2000-December/029972.html
( Particularly this:
https://mail.python.org/pipermail/python-list/2000-December/052694.html
)
Yet another "1" vs "True" debate:
https://mail.python.org/pipermail/python-list/2012-January/618649.html
New era:
https://mail.python.org/pipermail/python-list/2017-April/721182.html
___
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] Why is design-by-contracts not widely adopted?

2018-09-28 Thread Steven D'Aprano
On Sun, Sep 23, 2018 at 07:09:37AM +0200, Marko Ristin-Kaufmann wrote:

> After the discussion we had on the list and after browsing the internet a
> bit, I'm still puzzled why design-by-contract was not more widely adopted
> and why so few languages support it.
[...]

> *. *After properly reading about design-by-contract and getting deeper into
> the topic, there is no rational argument against it and the benefits are
> obvious. And still, people just wave their hand and continue without
> formalizing the contracts in the code and keep on writing them in the
> descriptions.
> 
> * Why is that so?
[...]

You are asking a question about human psychology but expecting logical, 
technical answers. I think that's doomed to failure.

There is no nice way to say this, because it isn't nice.

Programmers and language designers don't use DbC because it is new and 
different and therefore scary and wrong. Programmers, as a class, are 
lazy (they even call laziness a virtue), deeply conservative, 
superstitious, and don't like change. They do what they do because 
they're used to it, not because it is the technically correct thing to 
do, unless it is by accident.

(Before people's hackles raise too much, I'm speaking in generalities, 
not about you personally. Of course you are one of the 1% awesomely 
logical, technically correct programmers who know what you are doing and 
do it for the right reasons after careful analysis. I'm talking about 
the other 99%, you know the ones. You probably work with them. You've 
certainly read their answers on Stackoverflow or The Daily WTF and a 
million blogs.)

They won't use it until there is a critical mass of people using it, and 
then it will suddenly flip from "that weird shit Eiffel does" to "oh 
yeah, this is a standard technique that everyone uses, although we don't 
make a big deal about it".

Every innovation in programming goes through this. Whether the 
innovation goes mainstream or not depends on getting a critical mass, 
and that is all about psychology and network effects and nothing to do 
with the merit of the idea.

Remember the wars over structured programming? Probably not. In 2018, 
the idea that people would *seriously argue against writing subroutines* 
seems insane, but they did. As late as 1999, a former acquaintance of 
mine was working on a BASIC project for a manager who insisted they use 
GOTO and GOSUB in preference to subroutines.

Testing: the idea that we should have *repeatable automated tests* took 
a long time to be accepted, and is still resisted by both developers and 
their managers. What's wrong with just sitting a person down in front of 
the program and checking for bugs by hand? We still sometimes have to 
fight for an automated test suite, never mind something like test driven 
development.

ML-based languages have had type inference for decades, and yet people 
still think of type checking in terms of C and Java declarations. Or 
they still think in terms of static VERSUS dynamic typing, instead of 
static PLUS dynamic typing.

I could go on, but I think I've made my point.

I can give you some technical reasons why I don't use contracts in my 
own Python code, even though I want to:

(1) Many of my programs are too small to bother. If I'm writing a quick 
script, I don't even write tests. Sometimes "be lazy" is the right 
answer, when the cost of bugs is small enough and the effort to avoid 
them is greater. And that's fine. Nobody says that contracts must be 
mandatory.

(2) Python doesn't make it easy to write contracts. None of the 
solutions I've seen are nice. Ironically, the least worst I've seen is a 
quick and dirty metaclass solution given by Guido in an essay way back 
in Python 1.5 days:

https://www.python.org/doc/essays/metaclasses/

His solution relies only on a naming convention, no decorators, no 
lambdas:

class C(Eiffel):
def method(self, arg):
return whatever
def method_pre(self, arg):
assert arg > 0
def method_post(self, Result, arg):
assert Result > arg


Still not pretty, but at least we get some block structure instead of a 
wall of decorators.

Syntax matters. Without good syntax that makes it easy to write 
contracts, it will never be anything but niche.


(3) In a sense, *of course I write contracts*. Or at least precondition 
checks. I just don't call them that, and I embed them in the 
implementation of the method, and have no way to turn them off. Nearly 
all of us have done the same, we start with a method like this:

class C:
def method(self, alist, astring, afloat):
# do some work...

using nothing but naming conventions and an informal (and often vague) 
specification in the docstring, and while that is sometimes enough in 
small projects, the third time we get bitten we start adding defensive 
checks so we get sensible exceptions:

def method(self, alist, astring, afloat):
if not isinstance(alist, list):
raise 

Re: [Python-ideas] Why is design-by-contracts not widely

2018-09-28 Thread Dan Sommers

On 9/28/18 8:32 PM, Chris Angelico wrote:

On Sat, Sep 29, 2018 at 10:22 AM Dan Sommers
<2qdxy4rzwzuui...@potatochowder.com> wrote:


On 9/28/18 7:39 PM, Steven D'Aprano wrote:

But none of that compares to C undefined behaviour. People who think
that they are equivalent, don't understand C undefined behaviour.


Well, yes:  Some syntactically legal C results in nasal demons, and some
of that code is harder to spot than others.  AFAIK, syntactically legal
Python can only do that if the underlying C code invokes undefined
behaviour.


What should happen here?


[examples of what Steven would call non-sensible, non-non-weird objects
doing non-non-weird things snipped]

AFAIK, "AFAIK" is a weasel word:  It allows me to proclaim my own
ignorance without providing further examples, evidence, or counter
examples.  :-)


Python has its own set of "well don't do that then" situations. In
fact, I would say that *most* languages do.


Yep.
___
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] Why is design-by-contracts not widely adopted?

2018-09-28 Thread Dan Sommers

On 9/28/18 8:12 PM, Chris Angelico wrote:

On Sat, Sep 29, 2018 at 7:19 AM Greg Ewing  wrote:


Chris Angelico wrote:

It is still fundamentally difficult to make assertions about the file
system as pre/post contracts.


When you consider race conditions, I'd say it's impossible.
A postcondition check involving the file system could fail
even if the function does its job perfectly.


I guess that depends on the meaning of "contract". If it means "there
is a guarantee that this is true after this function returns", then
yes, the race condition means it's impossible. But as a part of the
function's declared intent, it's fine to have a postcondition of "the
directory will be empty" even though something could drop a file into
it.

But if it's the latter... contracts are just a different way of
defining unit tests and we're right back where we started.


At the risk of pedantry (on a Python list?  I'm *shocked*):

I call BS on any contract that requires on entry or guarantees on exit
the state of the file system.  At best, a function can guarantee that it
will make (or made) a request to the OS, and that the OS returned
"success" before the function continued.

Then again, a function that guarantees to work in a particular way based
on some condition of the file system would be okay.  For example, a
function might claim to create a temporary file with some content *if*
some directory exists when the function tries to create the temporary
file.  But as I think both of you are claiming, the best that function
can guarantee on exit is that it asked the OS to write to the file, and
that the OS agreed to do so.  The function cannot guarantee that the
file or the content still exists when the function finally returns.
___
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] Why is design-by-contracts not widely

2018-09-28 Thread Chris Angelico
On Sat, Sep 29, 2018 at 10:22 AM Dan Sommers
<2qdxy4rzwzuui...@potatochowder.com> wrote:
>
> On 9/28/18 7:39 PM, Steven D'Aprano wrote:
> > But none of that compares to C undefined behaviour. People who think
> > that they are equivalent, don't understand C undefined behaviour.
>
> Well, yes:  Some syntactically legal C results in nasal demons, and some
> of that code is harder to spot than others.  AFAIK, syntactically legal
> Python can only do that if the underlying C code invokes undefined
> behaviour.

What should happen here?

>>> import ctypes
>>> ctypes.cast(id(1), ctypes.POINTER(ctypes.c_int))[6] = 0
>>> 1

Nothing here invokes C's undefined behaviour. Or what about here:

>>> import sys; sys.setrecursionlimit(2147483647)
>>> def f(): f()
...
>>> f()


Python has its own set of "well don't do that then" situations. In
fact, I would say that *most* languages do.

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] Why is design-by-contracts not widely adopted?

2018-09-28 Thread Greg Ewing

Chris Angelico wrote:

But as a part of the
function's declared intent, it's fine to have a postcondition of "the
directory will be empty" even though something could drop a file into
it.


If you only intend the contract to serve as documentation,
I suppose that's okay, but it means you can't turn on runtime
checking of contracts, otherwise your program could suffer
spurious failures.

--
Greg
___
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] Why is design-by-contracts not widely

2018-09-28 Thread Dan Sommers

On 9/28/18 7:39 PM, Steven D'Aprano wrote:

On Fri, Sep 28, 2018 at 07:18:54PM +0200, 2qdxy4rzwzuui...@potatochowder.com 
wrote:


On 9/28/18 12:45 PM, Steven D'Aprano wrote:

On Tue, Sep 25, 2018 at 09:59:53PM +1000, Hugh Fisher wrote:


C and Python (currently) are known as simple languages.


o_O

That's a usage of "simple" I haven't come across before. Especially in
the case of C, which is a minefield of *intentionally* underspecified
behaviour which makes it near to impossible for the developer to tell
what a piece of syntactically legal C code will actually do in practice.


s/C/Python/

s/underspecified/dynamic/

;-)


I see the wink, but I don't see the relevance. Are you agreeing with me
or disagreeing?


I agree that Hugh's use of "simple" is unfamiliar.

I disagree that C is is a bigger offender than Python when it comes to a
developer telling what a piece of syntactically legal code will actually
do in practice.  If that's not what you meant by "Especially in the case
of C...," then I mis-interpreted or read too much into your wording.


Python is "simple" in the sense that the execution model is *relatively*
simple, but its not a minimalist language by any definition. And as you
say, the execution model is dynamic: we can't be sure what legal code
will do until you know the runtime state.


That's my point:  What you emphasized about C can be applied equally to
Python.  In C, it's because the standard is intentionally
underspecified; in Python, it's y because the language is intentionally
dynamic.

When you said "underspecified," I didn't make the leap to "undefined
behaviour" (although I think I know from past experience how you feel
about C and its undefined behaviour).  Instead, I jumped to things like
the ambiguity in the size of an int, or the freedom the compiler has to
pack/align struct values or implement integers as something other than
two's complement.


(Although we can often guess, based on assumptions about sensible,
non-weird objects that don't do weird things.)


Again, the same is true of C.  In Python, weird objects might override
getattr; in C weird objects might point to hardware registers, or depend
on implementation specific detail(s).


But none of that compares to C undefined behaviour. People who think
that they are equivalent, don't understand C undefined behaviour.


Well, yes:  Some syntactically legal C results in nasal demons, and some
of that code is harder to spot than others.  AFAIK, syntactically legal
Python can only do that if the underlying C code invokes undefined
behaviour.
___
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] Why is design-by-contracts not widely adopted?

2018-09-28 Thread Chris Angelico
On Sat, Sep 29, 2018 at 7:19 AM Greg Ewing  wrote:
>
> Chris Angelico wrote:
> > It is still fundamentally difficult to make assertions about the file
> > system as pre/post contracts.
>
> When you consider race conditions, I'd say it's impossible.
> A postcondition check involving the file system could fail
> even if the function does its job perfectly.

I guess that depends on the meaning of "contract". If it means "there
is a guarantee that this is true after this function returns", then
yes, the race condition means it's impossible. But as a part of the
function's declared intent, it's fine to have a postcondition of "the
directory will be empty" even though something could drop a file into
it.

But if it's the latter... contracts are just a different way of
defining unit tests and we're right back where we started.

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] Simplicity of C (was why is design-by-contracts not widely)

2018-09-28 Thread Hugh Fisher
> Date: Sat, 29 Sep 2018 02:45:06 +1000
> From: Steven D'Aprano 
> To: python-ideas@python.org
> Subject: Re: [Python-ideas] Why is design-by-contracts not widely
> Message-ID: <20180928164506.gn19...@ando.pearwood.info>
> Content-Type: text/plain; charset=us-ascii
>
> On Tue, Sep 25, 2018 at 09:59:53PM +1000, Hugh Fisher wrote:
>
> > C and Python (currently) are known as simple languages.
>
> o_O
>
> That's a usage of "simple" I haven't come across before. Especially in
> the case of C, which is a minefield of *intentionally* underspecified
> behaviour which makes it near to impossible for the developer to tell
> what a piece of syntactically legal C code will actually do in practice.

Oh FFS. You couldn't make the effort to read the very next sentence,
let alone the next paragraph, before responding?

-- 

cheers,
Hugh Fisher
___
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] Why is design-by-contracts not widely

2018-09-28 Thread Steven D'Aprano
On Fri, Sep 28, 2018 at 07:18:54PM +0200, 2qdxy4rzwzuui...@potatochowder.com 
wrote:
> 
> On 9/28/18 12:45 PM, Steven D'Aprano wrote:
> >On Tue, Sep 25, 2018 at 09:59:53PM +1000, Hugh Fisher wrote:
> >
> >>C and Python (currently) are known as simple languages.
> >
> >o_O
> >
> >That's a usage of "simple" I haven't come across before. Especially in
> >the case of C, which is a minefield of *intentionally* underspecified
> >behaviour which makes it near to impossible for the developer to tell
> >what a piece of syntactically legal C code will actually do in practice.
> 
> s/C/Python/
> 
> s/underspecified/dynamic/
> 
> ;-)

I see the wink, but I don't see the relevance. Are you agreeing with me 
or disagreeing?

Python is "simple" in the sense that the execution model is *relatively* 
simple, but its not a minimalist language by any definition. And as you 
say, the execution model is dynamic: we can't be sure what legal code 
will do until you know the runtime state.

(Although we can often guess, based on assumptions about sensible, 
non-weird objects that don't do weird things.)

But none of that compares to C undefined behaviour. People who think 
that they are equivalent, don't understand C undefined behaviour.

https://blog.regehr.org/archives/213

http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_14.html



-- 
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] Why is design-by-contracts not widely adopted?

2018-09-28 Thread James Lu
Many editors highlight decorators in a different color that makes it easier to 
ignore and can also fold decorators. 

Contracts can also sometimes actively improve the flow of code. 

I personally find a formal contract easier to read than informal documentation.

It also reduces the times where you need to spend time figuring out if 
documentation actually accurate and up to date
___
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] Exception handling in contracts

2018-09-28 Thread James Lu
Let’s get some ideas for how icontract can say “it should throw an exception if 
this happens.”
___
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] "old" values in postconditions

2018-09-28 Thread James Lu
> The problem with readability might be easier to solve than I thought, and 
> your pointer to coconut gave me the idea. What if we make a utility that 
> takes the python source code, examines the decorators pre/post/inv (or 
> whatever we call them) and transforms them back and forth from/to valid 
> python code?
> 
> Pretty much any IDE has after load / before save handlers. When you load a 
> python file, you'd transform it from less readable python code, write using a 
> concise form and when you save it, it's transformed back to valid python.
Hmm yes. Look at my previous email- the proposed syntax there does not require 
changing or transforming Python code. It’s missing many magic methods, but it 
would work something like this:

@snapshot(some_identifier=P.self.another_property + 10)

would internally turn into something like this: lambda P: 
P.self.another_property + 10

Maybe it’s possible to modify PyCharm parsing by altering its Python grammar 
file?

Sent from my iPhone

> On Sep 28, 2018, at 10:27 AM, Marko Ristin-Kaufmann  
> wrote:
> 
> Hi James,
> 
> The problem with readability might be easier to solve than I thought, and 
> your pointer to coconut gave me the idea. What if we make a utility that 
> takes the python source code, examines the decorators pre/post/inv (or 
> whatever we call them) and transforms them back and forth from/to valid 
> python code?
> 
> Pretty much any IDE has after load / before save handlers. When you load a 
> python file, you'd transform it from less readable python code, write using a 
> concise form and when you save it, it's transformed back to valid python.
> 
> Then we need to pick the python form that is easiest to implement (and still 
> readable enough for, say, code reviews on github), but writing and reading 
> the contracts in the code would be much more pleasant.
> 
> As long as the "readable" form has also valid python syntax, the tool can be 
> implemented with ast module.
> 
> For example:
> @snapshot(some_identifier=self.another_property + 10)
> @post(self.some_property => old.some_identifier > 100)
> 
> would transform into 
> @snapshot(lambda P, some_identifier: P.self.another_property + 10)
> @post(lambda O, P: not self.some_property and O.some_identifier > 100)
> 
> Cheers,
> Marko
> 
>> On Fri, 28 Sep 2018 at 03:49, Marko Ristin-Kaufmann  
>> wrote:
>> Hi James,
>> 
>> I still have a feeling that most developers would like to store the state in 
>> many different custom ways. I see also thunk and snapshot with wrapper 
>> objects to be much more complicated to implement and maintain; I'm thinking 
>> mostly about all the edge cases which we would not be able to cover (and how 
>> complex that would be to cover them). Then the linters need also to work 
>> around such wrappers... It might also scare users off since it looks like 
>> too much magic. Another concern I also have is that it's probably very hard 
>> to integrate these wrappers with mypy later -- but I don't really have a 
>> clue about that, only my gut feeling?
>> 
>> What about we accepted to repeat "lambda P, " prefix, and have something 
>> like this:
>> 
>> @snapshot(
>>   lambda P, some_name: len(P.some_property),
>>   lambda P, another_name: hash(P.another_property)
>> )
>> 
>> It's not too verbose for me and you can still explain in three-four 
>> sentences what happens below the hub in the library's docs.  A 
>> pycharm/pydev/vim/emacs plugins could hide the verbose parts. 
>> 
>> I performed a small experiment to test how this solution plays with pylint 
>> and it seems OK that arguments are not used in lambdas.
>> 
>> Cheers,
>> Marko
>> 
>> 
>>> On Thu, 27 Sep 2018 at 12:27, James Lu  wrote:
>>> Why couldn’t we record the operations  done to a special object and replay 
>>> them?
>>> 
>> Actually, I think there is probably no way around a decorator that 
>> captures/snapshots the data before the function call with a lambda (or 
>> even a separate function). "Old" construct, if we are to parse it 
>> somehow from the condition function, would limit us only to shallow 
>> copies (and be complex to implement as soon as we are capturing 
>> out-of-argument values such as globals etc.). Moreove, what if we don't 
>> need shallow copies? I could imagine a dozen of cases where shallow copy 
>> is not what the programmer wants: for example, s/he might need to make 
>> deep copies, hash or otherwise transform the input data to hold only 
>> part of it instead of copying (e.g., so as to allow equality check 
>> without a double copy of the data, or capture only the value of certain 
>> property transformed in some way).
>>> 
>>> 
>>> from icontract import snapshot, P, thunk
>>> @snapshot(some_identifier=P.self.some_method(P.some_argument.some_attr))
>>> 
>>> P is an object of our own type, let’s call the type MockP. MockP returns 
>>> new MockP objects when any operation is done to it. MockP * MockP = MockP. 
>>> MockP.attr = 

Re: [Python-ideas] "old" values in postconditions

2018-09-28 Thread James Lu
I am fine with your proposed syntax. It’s certainly lucid. Perhaps it would be 
a good idea to get people accustomed to “non-magic” syntax.

> I still have a feeling that most developers would like to store the state in 
> many different custom ways. 
Please explain. (Expressions like thunk(all)(a == b for a, b in P.arg.meth()) 
would be valid.)
> I'm thinking mostly about all the edge cases which we would not be able to 
> cover (and how complex that would be to cover them).

Except for a > b > c being one flat expression with 5 members, it seems fairly 
easy to recreate an AST, which can then be compiled down to a code object. The 
code object can be fun with a custom “locals()”

Below is my concept code for such a P object.

from ast import *
# not done: enforce Singleton property on EmptySymbolType
class EmptySymbolType(object): ...
EmptySymbol = EmptySymbolType() # empty symbols are placeholders
class MockP(object):
# "^" is xor
@icontract.pre(lambda symbol, astnode: (symbol is None) ^ (astnode is None))
def __init__(self, symbol=None, value=EmptySymbol, astnode=None, 
initsymtable=(,)):
self.symtable = dict(initsymtable)
if symbol:
self.expr = Expr(value=Name(id=symbol, ctx=Load()))
self.symtable = {symbol: value}
else:
self.expr = astnode
self.frozen = False
def __add__(self, other):
wrapped = MockP.wrap_value(other)
return MockP(astnode=Expr(value=BinOp(self.expr, Add(), wrapped.expr), 
initsymtable={**self.symtable, **wrapped.symtable})
def compile(self): ...
def freeze(self):
# frozen objects wouldn’t have an overrided getattr, allowing for 
icontract to manipulate the MockP object using its public interface
self.frozen = True
@classmethod
def wrap_value(cls, obj):
   # create a MockP object from a value. Generate a random identifier and 
set that as the key in symtable, the AST node is the name of that identifier, 
retrieving its value through simple expression evaluation.
   ...

thunk = MockP.wrap_value
P = MockP('P')
# elsewhere: ensure P is only accessed via valid “dot attribute access” inside 
@snapshot so contracts fail early, or don’t and allow Magic like __dict__ to 
occur on P.

> On Sep 27, 2018, at 9:49 PM, Marko Ristin-Kaufmann  
> wrote:
> 
> Hi James,
> 
> I still have a feeling that most developers would like to store the state in 
> many different custom ways. I see also thunk and snapshot with wrapper 
> objects to be much more complicated to implement and maintain; I'm thinking 
> mostly about all the edge cases which we would not be able to cover (and how 
> complex that would be to cover them). Then the linters need also to work 
> around such wrappers... It might also scare users off since it looks like too 
> much magic. Another concern I also have is that it's probably very hard to 
> integrate these wrappers with mypy later -- but I don't really have a clue 
> about that, only my gut feeling?
> 
> What about we accepted to repeat "lambda P, " prefix, and have something like 
> this:
> 
> @snapshot(
>   lambda P, some_name: len(P.some_property),
>   lambda P, another_name: hash(P.another_property)
> )
> 
> It's not too verbose for me and you can still explain in three-four sentences 
> what happens below the hub in the library's docs.  A pycharm/pydev/vim/emacs 
> plugins could hide the verbose parts. 
> 
> I performed a small experiment to test how this solution plays with pylint 
> and it seems OK that arguments are not used in lambdas.
> 
> Cheers,
> Marko
> 
> 
>> On Thu, 27 Sep 2018 at 12:27, James Lu  wrote:
>> Why couldn’t we record the operations  done to a special object and replay 
>> them?
>> 
> Actually, I think there is probably no way around a decorator that 
> captures/snapshots the data before the function call with a lambda (or 
> even a separate function). "Old" construct, if we are to parse it somehow 
> from the condition function, would limit us only to shallow copies (and 
> be complex to implement as soon as we are capturing out-of-argument 
> values such as globals etc.). Moreove, what if we don't need shallow 
> copies? I could imagine a dozen of cases where shallow copy is not what 
> the programmer wants: for example, s/he might need to make deep copies, 
> hash or otherwise transform the input data to hold only part of it 
> instead of copying (e.g., so as to allow equality check without a double 
> copy of the data, or capture only the value of certain property 
> transformed in some way).
>> 
>> 
>> from icontract import snapshot, P, thunk
>> @snapshot(some_identifier=P.self.some_method(P.some_argument.some_attr))
>> 
>> P is an object of our own type, let’s call the type MockP. MockP returns new 
>> MockP objects when any operation is done to it. MockP * MockP = MockP. 
>> MockP.attr = MockP. MockP objects remember all the operations done to them, 
>> 

Re: [Python-ideas] Why is design-by-contracts not widely adopted?

2018-09-28 Thread Greg Ewing

Chris Angelico wrote:

It is still fundamentally difficult to make assertions about the file
system as pre/post contracts.


When you consider race conditions, I'd say it's impossible.
A postcondition check involving the file system could fail
even if the function does its job perfectly.

--
Greg

___
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] Why is design-by-contracts not widely adopted?

2018-09-28 Thread Brendan Barnwell

On 2018-09-28 05:23, David Mertz wrote:

On Thu, Sep 27, 2018, 9:25 PM Marko Ristin-Kaufmann
mailto:marko.ris...@gmail.com>> wrote:

Try to question whether the contracts I wrote are so obvious to
everybody even if they are obvious to you and keep in mind that the
user does not look into the implementation.


I had missed this comment, but this seems to be the biggest disconnect,
or talking past each other.

I'm a user of many libraries. I USUALLY look at the implementation when
in doubt about a function. If contracts are meant only for users who
don't look at code, the detrimental effect on code readability is mitigated.


	I agree with you that this seems to be a major disconnect in the 
discussion here.  However, on the issue itself, I quite agree with Marko 
that it is *much* more important for the documentation to be readable 
than for the function to be readable.  I too read the source of 
functions sometimes, and whenever I find myself having to do so, I 
grouse at the authors of whatever libraries I'm using for not making the 
documentation more clear.  Ideally, no user should *ever* have to read 
the function source code, because the documentation should make it 
completely clear how to use the function without knowing *anything* 
about how it is implemented.


	Of course, this ideal will never be achieved, but I think it's 
something to aim towards, and the idea that adding a few lines of DbC 
decorators makes the source code too cluttered seems quite incorrect to 
me.  I glanced through the source code and didn't find it hard to read 
at all.  The contracts are all cleanly separated from the function 
bodies because they're in decorators up front.  I'm frankly quite 
baffled that other people on this thread find that hard to read.


	The problem with reading the source code is that you can't tell what 
parts of the behavior are specified and which are implementation 
details.  The appeal of something like DbC is that it encourages (some 
might say painfully forces) programmers to be very explicit about what 
behavior they want to guarantee.


	Whether writing these guarantees as Python expressions is better than 
writing them as prose is another matter.  Personally I do see some value 
in the modifications that Marko made to pathlib.  In a sense, writing 
"documentation as Python code" is like annotating the source code to 
mark which specific parts of the implementation are guarantees and which 
may be implementation details.  I think there is significant value in 
knowing precisely what an API allows, in an explicit and verifiable form 
such as that provided by DbC, rather than using human language, which is 
much less precise, can leave room for misinterpretation, and, perhaps 
most importantly, is harder to verify automatically.


	Ultimately, I'm firmly of the opinion that, in publicly distributed 
code, the function *IS* its documentation, not its source code.  When a 
function's actual behavior conflicts with its documented behavior, that 
is a bug.  When meaningful aspects of a functions behavior are not 
specified in the documentation, that is also a bug. These may be bugs in 
the documentation or in the behavior, but either way the point is that 
reading the source code is not an acceptable substitute for making the 
documentation a complete and self-sufficient vehicle for total 
understanding of the function's behavior.   It doesn't matter if the 
function behaves as the author intended; it only matters if it behaves 
as documented.


--
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
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Why is design-by-contracts not widely

2018-09-28 Thread 2qdxy4rzwzuuilue



On 9/28/18 12:45 PM, Steven D'Aprano wrote:

On Tue, Sep 25, 2018 at 09:59:53PM +1000, Hugh Fisher wrote:


C and Python (currently) are known as simple languages.


o_O

That's a usage of "simple" I haven't come across before. Especially in
the case of C, which is a minefield of *intentionally* underspecified
behaviour which makes it near to impossible for the developer to tell
what a piece of syntactically legal C code will actually do in practice.


s/C/Python/

s/underspecified/dynamic/

;-)


___
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] Why is design-by-contracts not widely

2018-09-28 Thread Steven D'Aprano
On Tue, Sep 25, 2018 at 09:59:53PM +1000, Hugh Fisher wrote:

> C and Python (currently) are known as simple languages.

o_O

That's a usage of "simple" I haven't come across before. Especially in 
the case of C, which is a minefield of *intentionally* underspecified 
behaviour which makes it near to impossible for the developer to tell 
what a piece of syntactically legal C code will actually do in practice.


-- 
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] Why is design-by-contracts not widely adopted?

2018-09-28 Thread Marko Ristin-Kaufmann
Hi,

(Posting from work, so sorry for the short response.)

@Paul Moore  icontract.pre/post/inv have the enabled
argument; if not enabled, the contract is ignored.

Similarly with rmdir() -- "the directory must be empty" -- but how exactly
>> am I supposed to check that?
>>
>
> Isn't that the whole point? The prose statement "the directory must be
> empty" is clear. But the exact code check isn't - and may be best handled
> by a series of unit tests, rather than a precondition.
>

I meant "check" as a user, not as a developer. As in "What did the
implementer think -- how am I supposed to check that the directory is
empty?" A la: "Dear user, if you want to rmdir, here is what you need to
check that it is indeed a dir, and here is what you need to check that it
is empty. If both checks pass, run me."

@David patching __doc__ automatically is on the short-term todo list. I
suppose we'll just add sphinx directives (:requires:, :ensures: etc.)

* Marko isn't that familiar with the codebase, so there may be better
> ways to express certain things
>

This is true :)

* Sometimes it's just plain hard to express a verbal constraint in code
>

In these cases you simply don't express it in code. Why would you? If it's
complex code, possibility that you have an error is probably equal or
higher than that your comment rots.

@pre(lambda args, result: not any(Path(arg).is_absolute() for arg in args)
> or
> (result == [pth for arg in args for pth in [Path(arg)] if
> pth.is_absolute()][-1]),
> "When several absolute paths are given, the last is taken as an anchor
> (mimicking os.path.join()’s behaviour)")
>

I'm really not familiar with the code base nor with how to write stuff nice
and succinct in python. This particular contract was hard to define because
there were no last() and no arg_is_absolute() functions.

Otherwise, it would have read:

@pre(lambda args, result: not any(arg_is_absolute(arg) for arg in args) or
result == Path(last(arg for arg in args if arg_is_absolute(arg)))

When rendered, this wouldn't look too bad to read.

@Chris

> It is still fundamentally difficult to make assertions about the file
> system as pre/post contracts. Are you becoming aware of this?
> Contracts, as has been stated multiple times, look great for
> mathematically pure functions that have no state outside of their own
> parameters and return values (and 'self', where applicable), but are
> just poor versions of unit tests when there's anything external to
> consider.
>

I never thought of these particular contracts as running in the production.
I would set them to run only in testing and only on part of the tests where
they are safe from race conditions (e.g., setting
enabled=test_pathlib.SERIAL; toggling mechanism is something I haven't
spent too much thought about either and would also need to be
discussed/implemented.).

I really thought about them as documentation, not for correctness (or at
best deeper tests during the testing in a "safe" local environment, for
example when you want to check if all the contracts also hold on situations
in *my *testsuite, not only during the test suite of pathlib).

In the end, I'm calling it the day. I really got tired in the last few
days. Standardizing contracts for python is not worth the pain. We'll
continue to develop icontract for our internal needs and keep it open
source, so anybody who's interested can have a look. Thank you all for a
very lively discussions!

Cheers,
Marko



On Fri, 28 Sep 2018 at 14:49, Paul Moore  wrote:

> On Fri, 28 Sep 2018 at 13:23, David Mertz  wrote:
> > I agree that all the Sphinx documentation examples shown are very nice.
> Prose descriptions would often be nicer still, but the Boolean expressions
> are helpful for those unusual cases where I don't want to look at the code.
>
> I'm ambivalent about the Sphinx examples. I find the highly detailed
> code needed to express a condition fairly unreadable (and I'm an
> experienced Python programmer). For example
>
> @pre(lambda args, result: not any(Path(arg).is_absolute() for arg in args)
> or
> (result == [pth for arg in args for pth in [Path(arg)] if
> pth.is_absolute()][-1]),
> "When several absolute paths are given, the last is taken as an anchor
> (mimicking os.path.join()’s behaviour)")
>
> The only way I'd read that is by looking at the summary text - I'd
> never get the sense of what was going on from the code alone. There's
> clearly a number of trade-offs going on here:
>
> * Conditions should be short, to avoid clutter
> * Writing helper functions that are *only* used in conditions is more
> code to test or get wrong
> * Sometimes it's just plain hard to express a verbal constraint in code
> * Marko isn't that familiar with the codebase, so there may be better
> ways to express certain things
>
> But given that *all* the examples I've seen of contracts have this
> issue (difficult to read expressions) I suspect the problem is
> inherent.
>
> Another thing that I haven't yet seen clearly explained. 

Re: [Python-ideas] Why is design-by-contracts not widely adopted?

2018-09-28 Thread Paul Moore
On Fri, 28 Sep 2018 at 13:23, David Mertz  wrote:
> I agree that all the Sphinx documentation examples shown are very nice. Prose 
> descriptions would often be nicer still, but the Boolean expressions are 
> helpful for those unusual cases where I don't want to look at the code.

I'm ambivalent about the Sphinx examples. I find the highly detailed
code needed to express a condition fairly unreadable (and I'm an
experienced Python programmer). For example

@pre(lambda args, result: not any(Path(arg).is_absolute() for arg in args) or
(result == [pth for arg in args for pth in [Path(arg)] if
pth.is_absolute()][-1]),
"When several absolute paths are given, the last is taken as an anchor
(mimicking os.path.join()’s behaviour)")

The only way I'd read that is by looking at the summary text - I'd
never get the sense of what was going on from the code alone. There's
clearly a number of trade-offs going on here:

* Conditions should be short, to avoid clutter
* Writing helper functions that are *only* used in conditions is more
code to test or get wrong
* Sometimes it's just plain hard to express a verbal constraint in code
* Marko isn't that familiar with the codebase, so there may be better
ways to express certain things

But given that *all* the examples I've seen of contracts have this
issue (difficult to read expressions) I suspect the problem is
inherent.

Another thing that I haven't yet seen clearly explained. How do these
contracts get *run*? Are they checked on every call to the function,
even in production code? Is there a means to turn them off? What's the
runtime overhead of a "turned off" contract (even if it's just an
if-test per condition, that can still add up)? And what happens if a
contract fails - is it an exception/traceback (which is often
unacceptable in production code such as services)? The lack of any
clear feel for the cost of adding contracts is part of what makes
people reluctant to use them (particularly in the face of the
unfortunately still common assertion that "Python is slow" :-()

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] Why is design-by-contracts not widely adopted?

2018-09-28 Thread David Mertz
On Thu, Sep 27, 2018, 9:25 PM Marko Ristin-Kaufmann 
wrote:

> Try to question whether the contracts I wrote are so obvious to everybody
> even if they are obvious to you and keep in mind that the user does not
> look into the implementation.
>

I had missed this comment, but this seems to be the biggest disconnect, or
talking past each other.

I'm a user of many libraries. I USUALLY look at the implementation when in
doubt about a function. If contracts are meant only for users who don't
look at code, the detrimental effect on code readability is mitigated.

The other place I look, if not the actual implementation, is at the
docstring. I don't remember if icontracts patches the docstring when it
decorates a function. If not, that would be very helpful.

I agree that all the Sphinx documentation examples shown are very nice.
Prose descriptions would often be nicer still, but the Boolean expressions
are helpful for those unusual cases where I don't want to look at the code.
___
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] Why is design-by-contracts not widely adopted?

2018-09-28 Thread David Mertz
On Fri, Sep 28, 2018, 4:38 AM Paul Moore  wrote:

> On Fri, 28 Sep 2018 at 02:24, Marko Ristin-Kaufmann <
> marko.ris...@gmail.com> wrote:
>
>> I annotated pathlib with contracts:
>> https://github.com/mristin/icontract-pathlib-poc. I zipped the HTML docs
>> into
>> https://github.com/mristin/icontract-pathlib-poc/blob/master/contracts-pathlib-poc.zip,
>> you can just unpack and view the index.html.
>>
>
> The thing that you didn't discuss in the above was the effect on the
> source code. Looking at your modified sources, I found it *significantly*
> harder to read your annotated version than the original. Basically every
> function and class was cluttered with irrelevant[1] conditions, which
> obscured the logic and the basic meaning of the code.
>

My reaction was just the same as Paul's. I read the modified source, and
found that the invariant declarations made it *dramatically* harder to
read. The ratio was almost exactly as I characterized in a recent note: 15
lines of pre/post-conditions on a 10 like function.

Like Paul, I understand the documentation and testing value of these, but
they were highly disruptive to the readability of the functions themselves.

As a result of reading the example, I'd be somewhat less likely to use a
DbC library, and much more strongly opposed to having one in the standards
library (and aghast at the idea of dedicated 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] Why is design-by-contracts not widely adopted?

2018-09-28 Thread Paul Moore
On Fri, 28 Sep 2018 at 10:37, Chris Angelico  wrote:
>
> On Fri, Sep 28, 2018 at 7:29 PM Jonathan Fine  wrote:
> >
> > I like this discussion. I'd like to add another theme, namely what
> > should happen when there is an error. (This is prompted by race
> > hazards when performing file system operations.)
> >
> > Suppose fn_a() calls fn_b(), and fn_b() raises an exception. What then
> > should fn_a() do? It may be that this exception has left part or all
> > of the system in an inconsistent (invalid) state.
>
> That's why try/finally exists. You shouldn't have to worry about
> contracts for that.
>
> (Similarly, context managers, which are a way of wrapping up
> try/finally into a convenient package.)

However, a contract would need to be able to express "Returns a fully
initialised widget or raises a BrokenWidget exception". Unit tests do
this sort of thing all the time.

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] Why is design-by-contracts not widely adopted?

2018-09-28 Thread Chris Angelico
On Fri, Sep 28, 2018 at 7:29 PM Jonathan Fine  wrote:
>
> I like this discussion. I'd like to add another theme, namely what
> should happen when there is an error. (This is prompted by race
> hazards when performing file system operations.)
>
> Suppose fn_a() calls fn_b(), and fn_b() raises an exception. What then
> should fn_a() do? It may be that this exception has left part or all
> of the system in an inconsistent (invalid) state.

That's why try/finally exists. You shouldn't have to worry about
contracts for that.

(Similarly, context managers, which are a way of wrapping up
try/finally into a convenient package.)

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] Why is design-by-contracts not widely adopted?

2018-09-28 Thread Jonathan Fine
I like this discussion. I'd like to add another theme, namely what
should happen when there is an error. (This is prompted by race
hazards when performing file system operations.)

Suppose fn_a() calls fn_b(), and fn_b() raises an exception. What then
should fn_a() do? It may be that this exception has left part or all
of the system in an inconsistent (invalid) state.

At this level of abstraction, it's not possible to sensibly answer
this question. Sometimes the whole system should be stopped. Other
times, an invalidation of an object is enough. And sometimes, a
rollback of the transaction is what's wanted.

Here's a well-known example (overflow exception in Ariane 5), which to
me shows that these problems can be very hard to get right.
https://en.wikipedia.org/wiki/Cluster_(spacecraft)

According to wikipedia (above) this failure resulted in "the first
example of large-scale static code analysis by abstract
interpretation".

I expect that in some situations design-by-contract will help here, by
encouraging a focus on providing a more complete specification of
behaviour. It would be good to have some real-life Python examples.
I'd afraid I don't have any (although I've looked either).

-- 
Jonathan
___
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] Why is design-by-contracts not widely adopted?

2018-09-28 Thread Chris Angelico
On Fri, Sep 28, 2018 at 11:25 AM Marko Ristin-Kaufmann
 wrote:
>
> Hi,
>
> I annotated pathlib with 
> contracts:https://github.com/mristin/icontract-pathlib-poc. I zipped the HTML 
> docs into 
> https://github.com/mristin/icontract-pathlib-poc/blob/master/contracts-pathlib-poc.zip,
>  you can just unpack and view the index.html.
>
> One thing I did observe was that there were contracts written in text all 
> over the documentation -- I tried to formulate most of them in code. Since 
> I'm not the implementer nor very familiar with the module, please consider 
> that many of these contracts can be definitely made more beautiful. There 
> were some limitations to icontract-sphinx extension and icontracts which I 
> noted at the top of the document.
>

You do a lot of contracts that involve is_absolute and other checks.
But the postcondition on is_absolute merely says:

not result or self.root != ""

(Also: I'm not sure, but I think maybe that should be _root?? Leaving
that aside.)

So I'm not sure how much you can really ascertain about absolute
paths. You guarantee that is_absolute will return something plausible,
but unless you guarantee that it's returning the correct value,
depending on it for your preconditions seems dubious. A buggy
is_absolute could break basically everything, and your contracts
wouldn't notice.

It is still fundamentally difficult to make assertions about the file
system as pre/post contracts. Are you becoming aware of this?
Contracts, as has been stated multiple times, look great for
mathematically pure functions that have no state outside of their own
parameters and return values (and 'self', where applicable), but are
just poor versions of unit tests when there's anything external to
consider.

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] Add .= as a method return value assignment operator

2018-09-28 Thread Chris Angelico
On Fri, Sep 28, 2018 at 6:56 PM Jonathan Fine  wrote:
> Finally, I note
>
> >>> a = 2
> >>> a **= 3
> >>> a
> 8
>

? Yes? That's what 2 ** 3 is, so that's what I would expect.

All other augmented assignment operators take an assignment target on
the left and a (single) value on the right.

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] Add .= as a method return value assignment operator

2018-09-28 Thread Jonathan Fine
Summary: I recast an example in a more abstract form.

Steve D'Aprano wrote:
> Think about a more complex assignment:
>text .= encode(spam) + str(eggs)

I find this example instructive. I hope the following is also instructive:

$ python3
>>> obj += incr
NameError: name 'obj' is not defined
>>> obj = object()
>>> obj += incr
NameError: name 'incr' is not defined
>>> incr = 1
>>> obj += incr
TypeError: unsupported operand type(s) for +=: 'object' and 'int'
>>> incr = object()
>>> obj += incr
TypeError: unsupported operand type(s) for +=: 'object' and 'object'
>>> obj +=  [] + ()
TypeError: can only concatenate list (not "tuple") to list

To me this shows that
LHS += RHS
works as follows:

1. Evaluate the LHS (as an assignable object).
2. Evaluate the RHS (as a value).

and then some more steps, not covered in my example.

As syntax the compound symbols '+=' and '.=' are similar. But in
semantics, '+=' does and '.=' does not have an evaluation of the RHS
as an expression. This is, in abstract terms, the origin of Steve's
example. Someone else has noted that '+=' and its variants are focused
on numeric operations, such as addition.

This shows, to me, that the simplification provided by use cases such as
text = text.replace("foo","bar")
has to be compared to the complexity introduced by
 text .= encode(spam) + str(eggs)

In other words, I've restated Steve's example, in a more abstract
form. I hope it helps to have another way to look at this example.

Finally, I note

>>> a = 2
>>> a **= 3
>>> a
8

-- 
Jonathan
___
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] Why is design-by-contracts not widely adopted?

2018-09-28 Thread Paul Moore
On Fri, 28 Sep 2018 at 02:24, Marko Ristin-Kaufmann 
wrote:

> Hi,
>
> I annotated pathlib with contracts:
> https://github.com/mristin/icontract-pathlib-poc. I zipped the HTML docs
> into
> https://github.com/mristin/icontract-pathlib-poc/blob/master/contracts-pathlib-poc.zip,
> you can just unpack and view the index.html.
>

Thanks, for doing this! It's probably not going to result in the reaction
you hoped for (see below) but I appreciate you taking the time to do it.

Some of the contracts might seem trivial -- but mind that you, as a writer,
> want to tell the user what s/he is expected to fulfill before calling the
> function. For example, if you say:
> rmdir()
>
> Remove this directory. The directory must be empty.
> Requires:
>
>- not list(self.iterdir()) (??? There must be a way to check this more
>optimally)
>- self.is_dir()
>
>
> self.is_dir() contract might seem trivial -- but it's actually not. You
> actually want to convey the message: dear user, if you are iterating
> through a list of paths, use this function to decide if you should call
> rmdir() or unlink(). Analogously with the first contract: dear user, please
> check if the directory is empty before calling rmdir() and this is what you
> need to call to actually check that.
>

The problem (IMO) with both of these is precisely that they are written as
Python expressions. Your prose descriptions of what they mean are fine, and
*those* are what I would hope to see in documentation. This is far more
obvious in later examples, where the code needed to check certain
conditions is extremely unclear unless you spend time trying to interpret
it.


> I also finally assembled the puzzle. Most of you folks are all older and
> were exposed to DbC in the 80ies championed by DbC zealots who advertised
> it as *the *tool for software development. You were repulsed by their
> fanaticism -- the zealots also pushed for all the contracts to be defined,
> and none less. Either you have 100% DbC or no sane software development at
> all.
>

Well, yes, but your claims were *precisely* the same as those I saw back
then. "All projects on PyPI would benefit", "the benefits are obvious", ...

As I said, DbC is a reasonable methodology, but the reason it's not more
widely used is (in the first instance) because it has a *marketing*
problem. Solving that with more of the same style of marketing won't help.
Once you get beyond the marketing, there are *still* questions (see above
and below), but if you can't even get people past the first step, you've
lost.


> And that's why I said that the libraries on pypi meant to be used by
> multiple people and which already have type annotations would obviously
> benefit from contracts -- while you were imagining that all of these
> libraries need to be DbC'ed 100%, I was imagining something much more
> humble. Thus the misunderstanding.
>

No, I was imagining that some libraries were small, some were used by
small, specialised groups, and some were immensely successful without DbC.
So claiming that they would "obviously" benefit is a very strong claim.


> After annotating pathlib, I find that it actually needs contracts more
> thain if it had type annotations. For example:
> stat()
>
> Return the result of the stat() system call on this path, like os.stat()
> does.
> Ensures:
>
>- result is not None ⇒ self.exists()
>- result is not None ⇒ os.stat(str(self)).__dict__ == result.__dict__
>(??? This is probably not what it was meant with ‘like os.stat() does’?)
>
>
> But what does it mean "like os.stat() does"? I wrote equality over
> __dict__'s in the contract. That was my idea of what the implementer was
> trying to tell me. But is that the operator that should be applied? Sure,
> the contract merits a description. But without it, how am I supposed to
> know what "like" means?
>
> Similarly with rmdir() -- "the directory must be empty" -- but how exactly
> am I supposed to check that?
>

Isn't that the whole point? The prose statement "the directory must be
empty" is clear. But the exact code check isn't - and may be best handled
by a series of unit tests, rather than a precondition.

Anyhow, please have a look at the contracts and let me know what you think.
> Please consider it an illustration. Try to question whether the contracts I
> wrote are so obvious to everybody even if they are obvious to you and keep
> in mind that the user does not look into the implementation. And please try
> to abstract away the aesthetics: neither icontract library that I wrote nor
> the sphinx extension are of sufficient quality. We use them for our company
> code base, but they still need a lot of polishing. So please try to focus
> only on the content. We are still talking about contracts in general, not
> about the concrete contract implementation
>

The thing that you didn't discuss in the above was the effect on the source
code. Looking at your modified sources, I found it *significantly* harder
to read your 

Re: [Python-ideas] Add .= as a method return value assignment operator

2018-09-28 Thread Steven D'Aprano
On Fri, Sep 28, 2018 at 05:34:58PM +1200, Greg Ewing wrote:
> Steven D'Aprano wrote:
> >Think about a more complex assignment:
> >
> >text .= encode(spam) + str(eggs)
> 
> I think the only sane thing would be to disallow that, and
> require the RHS to have the form of a function call, which is
> always interpreted as a method of the LHS.


You obviously have a different idea of what is "sane" than I do :-)

But okay, so we cripple the RHS so that it can only be a single method 
call. So useful things like these are out:

target .= method(arg) or default

target .= foo(arg) if condition else bar(arg)

and even 

target .= method(args) + 1

making the syntax pure sugar for

target = target.method(args)

and absolutely nothing else. I think that's the sort of thing which 
gives syntactic sugar a bad name.

The one positive I can see is that if the target is a compound 
expression, it could be evaluated once only:

spam[0](x, y, z).eggs['cheese'].aardvark .= method(args)

I suppose if I wrote a lot of code like that, aside from (probably?)
violating the Law of Demeter, I might like this syntax because it 
avoids repeating a long compound target.


-- 
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] Add .= as a method return value assignment operator

2018-09-28 Thread Jasper Rebane
I had the number 4 in mind
Though I think your idea is way better, as it's more flexible and less
confusing

On Fri, Sep 28, 2018, 10:33 Brice Parent  wrote:

>
> Le 27/09/2018 à 12:48, Ken Hilton a écrit :
>
> Hi Jasper,
> This seems like a great idea! It looks so much cleaner, too.
>
> Would there be a dunder method handling this? Or since it's explicitly
> just a syntax for "obj = obj.method()" is that not necessary?
> My only qualm is that this might get PHP users confused; that's really not
> an issue, though, since Python is not PHP.
>
> Anyway, I fully support this idea.
>
> What would the following evaluate to?
> a .= b + c(d)
>
> 1: a = a.b + a.c(a.d)  # everything is prepended an "a."
> it means we dn't have access to any external elements, making the
> functionality only useful in a few cases
>
> 2: a = a.b + a.c(d)  # every first level element (if that means something)
> is prepended an "a."
> We still lose some of the ability to access anything outside of `a`, but a
> bit less than in #1. The effort to understand the line as grown a bit,
> though.
>
> 3: a = a.(b + c(d))  # everything is evaluated, and an "a." is prepended
> to that result
> (the same way `a *= 2 + 3` is equivalent to `a *= 5`)
> I believe in most cases, this wouldn't mean anything to evaluate `b +
> c(d)` on their own, and expect a return that can be used as an attribute of
> `a`.
>
> 4: a = a.b + c(d)  # "a." is prepended to the first element after the `=`
> It is probably quite easy to read and understand, but it removes the
> transitivity of the operators we have on the right, and is a bit limiting.
>
> 5: SyntaxError: Can only use the [whatever the name] augmented operator
> with a single expression
> Why not, it's a bit limiting, but is clear enough to me.
>
> Maybe, a simpler thing to do for this problem would be to make something
> like this:
> a = .b(5) + c(.d) + 3
> being the equivalent of
> a = a.b(5) + c(a.d) + 3
>
> I don't see any ambiguity anymore, it shortens the code a lot, and I guess
> it wouldn't be hard for the compiler to recompose the line as a first
> parsing step, and create the same AST with both syntaxes.
> ___
> 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] Add .= as a method return value assignment operator

2018-09-28 Thread Brice Parent


Le 27/09/2018 à 12:48, Ken Hilton a écrit :

Hi Jasper,
This seems like a great idea! It looks so much cleaner, too.

Would there be a dunder method handling this? Or since it's explicitly 
just a syntax for "obj = obj.method()" is that not necessary?
My only qualm is that this might get PHP users confused; that's really 
not an issue, though, since Python is not PHP.


Anyway, I fully support this idea.


What would the following evaluate to?
a .= b + c(d)

1: a = a.b + a.c(a.d)  # everything is prepended an "a."
it means we dn't have access to any external elements, making the 
functionality only useful in a few cases


2: a = a.b + a.c(d)  # every first level element (if that means 
something) is prepended an "a."
We still lose some of the ability to access anything outside of `a`, but 
a bit less than in #1. The effort to understand the line as grown a bit, 
though.


3: a = a.(b + c(d))  # everything is evaluated, and an "a." is prepended 
to that result

(the same way `a *= 2 + 3` is equivalent to `a *= 5`)
I believe in most cases, this wouldn't mean anything to evaluate `b + 
c(d)` on their own, and expect a return that can be used as an attribute 
of `a`.


4: a = a.b + c(d)  # "a." is prepended to the first element after the `=`
It is probably quite easy to read and understand, but it removes the 
transitivity of the operators we have on the right, and is a bit limiting.


5: SyntaxError: Can only use the [whatever the name] augmented operator 
with a single expression

Why not, it's a bit limiting, but is clear enough to me.

Maybe, a simpler thing to do for this problem would be to make something 
like this:

a = .b(5) + c(.d) + 3
being the equivalent of
a = a.b(5) + c(a.d) + 3

I don't see any ambiguity anymore, it shortens the code a lot, and I 
guess it wouldn't be hard for the compiler to recompose the line as a 
first parsing step, and create the same AST with both syntaxes.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/