Re: Status of side-effecting functions in python

2014-10-28 Thread Marko Rauhamaa
Nobody nobody@nowhere.invalid:

 Asynchronous I/O in the sense of select(), poll(), O_NONBLOCK etc is
 meant for situations where delays could be indefinite, e.g. network
 connections or terminals. For short delays (i.e. disc access),
 there's not much point having a mechanism so that you can avoid
 blocking while the data is read from disc just so that you can block
 while the code in the else branch is read from disc.

I disagree with the shortness of the delays.

 If you want the program to be able to do something else while waiting
 for I/O, use threads. The introduction of threads made most
 concurrency- related issues in the POSIX API moot.

I disagree about that point of view as well. If files played ball with
select() et al, the linux world would be a better, more coherent place.

For example, looking at Python3's asyncio, I don't want to go out of the
asyncio model just because of disk (or DB) access.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-28 Thread Marko Rauhamaa
Marko Rauhamaa ma...@pacujo.net:

 Python's sockets and pipes don't have write methods.

Actually, that's mistaken as well. The sys.std* handles and pipes
returned by subprocess are accessed using file.write() and thus may
return partial writes.

That brings up another point: Python3's file.write() returns the number
of characters written. What might it return if a partial character
should be written?


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-27 Thread Steven D'Aprano
Roy Smith wrote:

 Yes and no. If something goes wrong in a .write() method,
 is not Python supposed to raise an error? (!)
 
 Define wrong.  It is not an error for a write() call to consume fewer
 bytes than were requested.  

It's not? I'm asking a genuine question here, not a rhetorical one. I would
expect that if I ask to write 2 bytes, and only 1 byte is written, that
absolutely is an error. Under what circumstances is it okay for write() to
throw data away?

 How would you expect this to be handled in Python?  Raise
 DataPartiallyWrittenError? 

I would expect it to raise an IOError, most likely with one of the following
error codes:

* errno.EIO (physical input/output error)

* errno.EFBIG (file is too large)

* errno.ENOSPC (no space left on device, disk is full)


-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-27 Thread Chris Angelico
On Mon, Oct 27, 2014 at 10:30 PM, Steven D'Aprano
steve+comp.lang.pyt...@pearwood.info wrote:
 Roy Smith wrote:

 Yes and no. If something goes wrong in a .write() method,
 is not Python supposed to raise an error? (!)

 Define wrong.  It is not an error for a write() call to consume fewer
 bytes than were requested.

 It's not? I'm asking a genuine question here, not a rhetorical one. I would
 expect that if I ask to write 2 bytes, and only 1 byte is written, that
 absolutely is an error. Under what circumstances is it okay for write() to
 throw data away?

 How would you expect this to be handled in Python?  Raise
 DataPartiallyWrittenError?

 I would expect it to raise an IOError, most likely with one of the following
 error codes:

 * errno.EIO (physical input/output error)

 * errno.EFBIG (file is too large)

 * errno.ENOSPC (no space left on device, disk is full)

You're assuming the condition, whatever it is, is permanent. The most
common reason for write() to be temporarily unable to write everything
is a non-blocking socket, pipe, or somesuch. It writes as much as it
can, tells you how much that is, and lets you buffer the rest or deal
with it in whatever other way you choose.

If it is permanent, though, then yes, it should tell you. But what if
you ask it to write a megabyte, it writes half of it, and then finds
that there's no space on the disk? Should it:

1) Back out the write and raise an exception?
2) Write part of the data and raise an exception?
3) Write part of the data and NOT raise an exception?

All three make sense. The third one is an option only if it's
documented as being able to tell you about partial writes. The second
has a problem in that you can't necessarily communicate this is how
much I wrote properly while also signalling the exception (imagine if
one function calls write() more than once, and it doesn't catch any
exceptions, just lets them bubble up). And backing out a write isn't
always possible. So what's to do?

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-27 Thread Roy Smith
In article 544e2cf2$0$13009$c3e8da3$54964...@news.astraweb.com,
 Steven D'Aprano steve+comp.lang.pyt...@pearwood.info wrote:

 Roy Smith wrote:
 
  Yes and no. If something goes wrong in a .write() method,
  is not Python supposed to raise an error? (!)
  
  Define wrong.  It is not an error for a write() call to consume fewer
  bytes than were requested.  
 
 It's not? I'm asking a genuine question here, not a rhetorical one. I would
 expect that if I ask to write 2 bytes, and only 1 byte is written, that
 absolutely is an error. Under what circumstances is it okay for write() to
 throw data away?

It's not throwing away data.  The write() call returns a count of how 
many bytes is consumed, so you can present the rest of them again in a 
later write() call (assuming that makes sense to do for your 
application).

In some cases, the underlying hardware (or network protocol) may be 
unable to handle the number of bytes you requested, or may fail in 
mid-transmission.  Imagine a serial link.  You tell it to write 100 
bytes.  It starts sending them down the line and after 20 bytes, the 
connection fails.  What should write() do in that case?  It hasn't 
written all the data, so it needs to let you know that.  It also has 
written *some* of the data, so it needs to let you know that too.  What 
you do with that information is up to you, but it clearly needs to 
return a richer status indication than just success/failure.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-27 Thread Grant Edwards
On 2014-10-25, Wolfgang Maier wolfgang.ma...@biologie.uni-freiburg.de wrote:

 It may be rare to use an expression both for its side-effects and its
 return value,

It's actually quite common.

For example:

   f = open(filename)
   d = f.readline()

In both of those lines, the side effects and return values are equally
vital.  The same applies to reading from a queue, popping from a
stack, etc.

-- 
Grant Edwards   grant.b.edwardsYow! This PORCUPINE knows
  at   his ZIPCODE ... And he has
  gmail.comVISA!!
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-27 Thread Grant Edwards
On 2014-10-27, Steven D'Aprano steve+comp.lang.pyt...@pearwood.info wrote:
 Roy Smith wrote:

 Yes and no. If something goes wrong in a .write() method,
 is not Python supposed to raise an error? (!)
 
 Define wrong.  It is not an error for a write() call to consume fewer
 bytes than were requested.  

 It's not? I'm asking a genuine question here, not a rhetorical one.

No.  

Under Unix/Posix a write() call may _always_ write fewer bytes than
requested.

It may be that the device/pipe/file whatever has filled and blocking
is disabled.  It may be that the device has decided that, at the
moment, it can only handle a certain amount of data for some other
reason.  For example: Let's say you're writing to a network connection
that must segment data, and you try to write more than will fit in the
current segment. The write() call may fill the segment, send the
segment, and refuse the rest of the data -- requiring that you make
a subsequent write() with the remaining data (at which point it will
start a new segment).

Or, it may be because the system call was interrupted by something
completely unrelated to your program, the write() call, or the thing
to which you're writing [and it was more convenient for whoever wrote
the OS to do a partial write than it was to try to resume the write].

If you really want to make sure that all bytes get written, you _must_
put all write() calls in a loop that checks the return value and keeps
re-writing any unwritten data.

And to answer your next question: yes, Unix application programmers
have been complaining about that (perhaps justifiably) since 1970.

-- 
Grant Edwards   grant.b.edwardsYow! I have a TINY BOWL in
  at   my HEAD
  gmail.com
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-27 Thread Marko Rauhamaa
Grant Edwards invalid@invalid.invalid:

 If you really want to make sure that all bytes get written, you _must_
 put all write() calls in a loop that checks the return value and keeps
 re-writing any unwritten data.

 And to answer your next question: yes, Unix application programmers
 have been complaining about that (perhaps justifiably) since 1970.

I wouldn't have it any other way.

Now, I have confused the discussion with some misinformation myself.
Python2's file.write() doesn't return a value but pushes the whole
string out. Python3's file.write() returns the number of *characters*
written. I don't know if the number can ever be different from the total
number of characters in the string.

In POSIX, a write(2) system call on file blocks until all bytes have
been passed on to the file system. The only exception (no pun intended)
I know is the reception of a signal. Even then, I'm not sure Linux file
systems ever cut writes short because of signals. I think the lack of
nonblocking file access in Linux is one of the OS's main shortcomings.

Python's sockets and pipes don't have write methods.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-27 Thread Nobody
On Mon, 27 Oct 2014 17:14:58 +0200, Marko Rauhamaa wrote:

 In POSIX, a write(2) system call on file blocks until all bytes have been
 passed on to the file system. The only exception (no pun intended) I know
 is the reception of a signal.

Writing to a file (or block device) will return a short count in the event
that it results in the size of the file exceeding

* the space available on the partition,
* the user's quota,
* the process' file size limit (RLIMIT_FSIZE), or
* any implementation limit on the maximum size of a file,

and at least one byte can be written. This behaviour is mandated by POSIX.

This is different to writing to a socket, pipe or character device,
where a short count is considered an entirely normal result, and
a subsequent write for the remaining bytes will often succeed.

 Even then, I'm not sure Linux file systems ever cut writes short because
 of signals.

Linux never interrupts I/O on discs or block devices due to signals.
These are restarted regardless of whether the signal is set for
automatic restarting (SA_RESTART flag).

 I think the lack of nonblocking file access in Linux is one of the OS's
 main shortcomings. 

It doesn't really matter. In the absence of an explicit mlock() or
mlockall(), the actual code which would be controlling the access is
demand-paged from disc, as is the memory to/from which the data is
transferred (along with the memory which would hold the return code from
read() or write(), for that matter).

Asynchronous I/O in the sense of select(), poll(), O_NONBLOCK etc is meant
for situations where delays could be indefinite, e.g. network connections
or terminals. For short delays (i.e. disc access), there's not much
point having a mechanism so that you can avoid blocking while the data is
read from disc just so that you can block while the code in the else
branch is read from disc.

If you want the program to be able to do something else while waiting for
I/O, use threads. The introduction of threads made most concurrency-
related issues in the POSIX API moot.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-26 Thread Dan Sommers
On Sun, 26 Oct 2014 00:45:49 -0700, wxjmfauth wrote:

 Ditto for fileobj.write(). Why should it return something ?
 
 with open('z.txt', 'w') as f:
 ... f.write('abc')
 ... 
 3

OTOH, why shouldn't it return something?  In this case, it returns the
length of the string written.  This value is analogous to the value
returned by the underlying OS function (at least on a POSIX-like system,
where write(2) returns the number of bytes written).  This value can be
useful for detecting when things have gone wrong; e.g., disk full,
network down, pipe broken, etc.  Practicality definitely beats purity.

At one time, on a huge project, millions of lines of C and assembly
code, we had a local guideline *not* to write void functions.  The idea
was to return something that might be useful later, even if it seemed
unlikely now.  A simple success flag was sufficient; as functions grew,
often did their failure modes.

Dan
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-26 Thread Rustom Mody
On Sunday, October 26, 2014 7:11:43 PM UTC+5:30, Dan Sommers wrote:

 At one time, on a huge project, millions of lines of C and assembly
 code, we had a local guideline *not* to write void functions.  The idea
 was to return something that might be useful later, even if it seemed
 unlikely now.  A simple success flag was sufficient; as functions grew,
 often did their failure modes.

Well C and Python are completely different in this respect.
In C it is the norm to return the status in the return value
and the actual return value in pointer parameters.

Or even worse in pointer parameters + globals: think of most of the
system calls and errno.

This low-level messiness is in fact one of the compulsions that
have driven preference and development of higher level languages
like python.  Here failure-mode has dedicated syntax -- exceptions.  This 
conduces to a more DRY, less error-prone setup.

- Normal mode in the normal functional call-return style
- Failure mode in the except (for caller); raise (for callee) clauses.


Note that my comment was:

 Its generally accepted that side-effecting functions are not a good idea
 -- typically a function that returns something and changes global state. 

So I am not talking of merely global (or non-local) variable
side-effecting functions/methods which is normal in imperative
programming, but ones that do BOTH

- both changing global state
- returning useful results in the return value

While this may be called a code-smell, in C like languages it is
close to unavoidable.

In python its more avoidable and therefore more smelly (to my nose at least!)

Yeah I note Terry's examples of list.pop etc.
I guess one could say that these are instances of practicality beats purity.

However note the context where this thread arose.
A beginning programmer having a hard time distinguishing:

- Values and effects
- Expressions and statements
- Immutable and mutable data-structures
- Functions and Procedures

My claim is that until then, he should not be trying to write code like that.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-26 Thread Marko Rauhamaa
wxjmfa...@gmail.com:

 Yes and no. If something goes wrong in a .write() method,
 is not Python supposed to raise an error? (!)

We have multiple cases:

 1. write succeeds with all of the given bytes

 2. write succeeds with some but not all of the given bytes

 3. write cannot at the moment write any bytes

 4. an I/O error has taken place

Cases 1 and 2 are reported through positive return values in POSIX
system calls. Cases 3 and 4 are reported as errors. Arguably 2 and 3 are
related cases.

Python imitates POSIX, but *could* take a different tack. For example,

 * always return with an exception carrying the number of bytes written

 * return with None in case 1 and with an exception otherwise

 * return with the number of bytes in 1, 2 and 3 and exception in 4

The POSIX way is justified with symmetry: read() distinguishes EAGAIN
from 0 (end of file). One could argue that POSIX got it the wrong way.
EOF should be an exception (EEOF) and 0 should be used instead of
EAGAIN. However, the POSIX practice works in C and Python.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-26 Thread Roy Smith
In article 683c84d8-d916-4b63-b4b2-92cd2763e...@googlegroups.com,
 wxjmfa...@gmail.com wrote:

 Le dimanche 26 octobre 2014 14:41:43 UTC+1, Dan Sommers a écrit :
  On Sun, 26 Oct 2014 00:45:49 -0700, wxjmfauth wrote:
  
   Ditto for fileobj.write(). Why should it return something ?
   
   with open('z.txt', 'w') as f:
   ... f.write('abc')
   ... 
   3
  
  OTOH, why shouldn't it return something?  In this case, it returns the
  length of the string written.  This value is analogous to the value
  returned by the underlying OS function (at least on a POSIX-like system,
  where write(2) returns the number of bytes written).  This value can be
  useful for detecting when things have gone wrong; e.g., disk full,
  network down, pipe broken, etc.  Practicality definitely beats purity.
  
  At one time, on a huge project, millions of lines of C and assembly
  code, we had a local guideline *not* to write void functions.  The idea
  was to return something that might be useful later, even if it seemed
  unlikely now.  A simple success flag was sufficient; as functions grew,
  often did their failure modes.
  
  Dan
 
 Yes and no. If something goes wrong in a .write() method,
 is not Python supposed to raise an error? (!)

Define wrong.  It is not an error for a write() call to consume fewer 
bytes than were requested.  How would you expect this to be handled in 
Python?  Raise DataPartiallyWrittenError?
-- 
https://mail.python.org/mailman/listinfo/python-list


Status of side-effecting functions in python

2014-10-25 Thread Rustom Mody
Moved from other (Seymore's) thread where this is perhaps not relevant

On Saturday, October 25, 2014 1:15:09 PM UTC+5:30, Steven D'Aprano wrote:
 Rustom Mody wrote:
 
  On Saturday, October 25, 2014 11:20:03 AM UTC+5:30, Chris Angelico wrote:
  On Sat, Oct 25, 2014 at 4:40 PM, Rustom Mody  wrote:
   Its generally accepted that side-effecting functions are not a good
   idea -- typically a function that returns something and changes global
   state.
  
  Only in certain circles. Not in Python. There are large numbers of
  functions with side effects (mutator methods like list.append,
  anything that needs lots of state like random.random, everything with
  external effect like I/O, heaps of stuff), and it is most definitely
  not frowned upon.
  
  In Python 3 (or Python 2 with the future directive), print is a
  function, print() an expression. It's not semantically a statement.
  
  Ok
  So give me a valid (ie useful) use where instead of the usual
  l=[1,2,3]
  l.append(4)
  
  we have
  
  foo(l.append(4))
 
 Your question seems to be non-sequitor. To me, it doesn't appear to have any
 relationship to Chris' comments.

| Languages like Pascal (many others)... distinguish function which return
| results and procedure which do not...
| Extract from https://en.wikipedia.org/wiki/Subroutine#Language_support

So my point: Whether the language supports it strongly (Pascal'
procedures) weakly (C's void functions) more weakly (Python's None
returning functions), the beginning programmer needs this concept as a core
thinking tool.

Pascal makes this easy -- teach the syntax and the concept will get across
Python is harder because the concept does not correlate with any specific syntax
But its not all that hard unless the teacher is stuck in correlating core 
concepts
and language syntax.

A teacher who is so stuck is cheating the student.

My version: 
print may (3) or may not (2) be an expression. Just always consider it as a 
statement

Chris version: print() is an expression. 
Technically Chris is correct. Is it methodologically/pedagogically it is sound?

Consider:

From my explanation this:

 [print(x) for x in [1,2,3]]
1
2
3
[None, None, None]
 

is in Dont Do! category whether python (3) allows it or python 2 doesn't.
And you Dont do because print(x) is a statement -- literally in
python 2; morally in python 3

And from here its only a small step to why l.append(4) should never
be used except as a statement. Python may not literally have Pascal's 
procedures;
they are morally there if you choose to 'believe' in them.

How would Chris inculcate avoidance of code-smells like
- foo(l.append(4))
- [print(x) for x in [1,2,3]]

  ?

No idea!

I dare say: about print I dont know but
[foo(x) for x in lst]
and foo is used for effect not return-value is
a rather common code-smell in my experience
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-25 Thread Wolfgang Maier

On 25.10.2014 19:27, Rustom Mody wrote:

Moved from other (Seymore's) thread where this is perhaps not relevant

On Saturday, October 25, 2014 1:15:09 PM UTC+5:30, Steven D'Aprano wrote:

Rustom Mody wrote:


On Saturday, October 25, 2014 11:20:03 AM UTC+5:30, Chris Angelico wrote:

On Sat, Oct 25, 2014 at 4:40 PM, Rustom Mody  wrote:

Its generally accepted that side-effecting functions are not a good
idea -- typically a function that returns something and changes global
state.


Only in certain circles. Not in Python. There are large numbers of
functions with side effects (mutator methods like list.append,
anything that needs lots of state like random.random, everything with
external effect like I/O, heaps of stuff), and it is most definitely
not frowned upon.

In Python 3 (or Python 2 with the future directive), print is a
function, print() an expression. It's not semantically a statement.


Ok
So give me a valid (ie useful) use where instead of the usual
l=[1,2,3]
l.append(4)

we have

foo(l.append(4))


Your question seems to be non-sequitor. To me, it doesn't appear to have any
relationship to Chris' comments.


| Languages like Pascal (many others)... distinguish function which return
| results and procedure which do not...
| Extract from https://en.wikipedia.org/wiki/Subroutine#Language_support

So my point: Whether the language supports it strongly (Pascal'
procedures) weakly (C's void functions) more weakly (Python's None
returning functions), the beginning programmer needs this concept as a core
thinking tool.

Pascal makes this easy -- teach the syntax and the concept will get across
Python is harder because the concept does not correlate with any specific syntax
But its not all that hard unless the teacher is stuck in correlating core 
concepts
and language syntax.

A teacher who is so stuck is cheating the student.

My version:
print may (3) or may not (2) be an expression. Just always consider it as a 
statement

Chris version: print() is an expression.
Technically Chris is correct. Is it methodologically/pedagogically it is sound?

Consider:

 From my explanation this:


[print(x) for x in [1,2,3]]

1
2
3
[None, None, None]




is in Dont Do! category whether python (3) allows it or python 2 doesn't.
And you Dont do because print(x) is a statement -- literally in
python 2; morally in python 3

And from here its only a small step to why l.append(4) should never
be used except as a statement. Python may not literally have Pascal's 
procedures;
they are morally there if you choose to 'believe' in them.

How would Chris inculcate avoidance of code-smells like
- foo(l.append(4))
- [print(x) for x in [1,2,3]]



As Chris and Steven have pointed out, picking print() as an example does 
not make too much sense since it returns None.
It may be rare to use an expression both for its side-effects and its 
return value, but, provided you document the intention appropriately, I 
do not see what would generally be wrong with it.


A quick example that's not quite as silly as all your print() ones:

 with open('longnumber.txt', 'w') as out:
print(sum(out.write(str(x)) for x in range(100)), 'characters written.')


190 characters written.


--
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-25 Thread Dan Sommers
On Sat, 25 Oct 2014 23:41:52 +0200, Wolfgang Maier wrote:

 ... It may be rare to use an expression both for its side-effects and
 its return value ...

A lot of concurrency-related operations work that way.  In the old days,
it was CPU-level Test and Set (or Compare and Set) instructions.  These
days, we have Python's threading.Lock.acquire.

Dan
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Status of side-effecting functions in python

2014-10-25 Thread Terry Reedy

On 10/25/2014 6:22 PM, Dan Sommers wrote:

On Sat, 25 Oct 2014 23:41:52 +0200, Wolfgang Maier wrote:


... It may be rare to use an expression both for its side-effects and
its return value ...


A lot of concurrency-related operations work that way.  In the old days,
it was CPU-level Test and Set (or Compare and Set) instructions.  These
days, we have Python's threading.Lock.acquire.


list.pop and and related set and dict methods.

--
Terry Jan Reedy

--
https://mail.python.org/mailman/listinfo/python-list