Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #44944 > unrolled thread

object.enable() anti-pattern

Started bySteven D'Aprano <steve+comp.lang.python@pearwood.info>
First post2013-05-08 08:52 +0000
Last post2013-05-13 08:15 -0500
Articles 20 on this page of 82 — 23 participants

Back to article view | Back to comp.lang.python


Contents

  object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-08 08:52 +0000
    Re: object.enable() anti-pattern Christian Heimes <christian@python.org> - 2013-05-08 11:51 +0200
    Re: object.enable() anti-pattern Robert Kern <robert.kern@gmail.com> - 2013-05-08 11:13 +0100
      Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-08 12:30 +0000
    Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-08 09:17 -0400
    Re: object.enable() anti-pattern Duncan Booth <duncan.booth@invalid.invalid> - 2013-05-08 14:27 +0000
      Re: object.enable() anti-pattern Dan Sommers <dan@tombstonezero.net> - 2013-05-09 02:38 +0000
        Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-09 05:37 +0000
          Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-09 15:52 +1000
      Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-09 03:12 +0000
    Re: object.enable() anti-pattern Dan Sommers <dan@tombstonezero.net> - 2013-05-09 02:42 +0000
      Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-09 05:23 +0000
        Re: object.enable() anti-pattern Terry Jan Reedy <tjreedy@udel.edu> - 2013-05-09 02:41 -0400
        Re: object.enable() anti-pattern Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2013-05-09 19:54 +1200
          Re: object.enable() anti-pattern Cameron Simpson <cs@zip.com.au> - 2013-05-09 18:23 +1000
            Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-09 11:30 +0000
              Re: object.enable() anti-pattern Cameron Simpson <cs@zip.com.au> - 2013-05-10 09:36 +1000
                Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-10 05:00 +0000
                  Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-10 01:50 -0400
                    Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-10 09:47 +0000
                      Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-10 09:22 -0400
                        Re: object.enable() anti-pattern Cameron Simpson <cs@zip.com.au> - 2013-05-11 08:25 +1000
                        Re: object.enable() anti-pattern Mark Janssen <dreamingforward@gmail.com> - 2013-05-10 20:16 -0700
                        Re: object.enable() anti-pattern Thomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de> - 2013-05-11 06:21 +0200
                        Re: object.enable() anti-pattern Mark Janssen <dreamingforward@gmail.com> - 2013-05-10 21:00 -0700
                  Re: object.enable() anti-pattern Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-05-11 15:04 -0400
          Re: object.enable() anti-pattern Greg Ewing <greg.ewing@canterbury.ac.nz> - 2013-05-10 10:56 +1200
        Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-09 09:07 -0400
          Re: object.enable() anti-pattern Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-05-09 14:51 +0100
          Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-09 18:21 +0000
            Re: object.enable() anti-pattern MRAB <python@mrabarnett.plus.com> - 2013-05-09 19:34 +0100
              Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-10 02:30 +0000
                Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-09 23:09 -0400
                  Re: object.enable() anti-pattern Mark Janssen <dreamingforward@gmail.com> - 2013-05-09 20:19 -0700
                  Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-10 13:46 +1000
                  Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-10 05:03 +0000
                    Re: object.enable() anti-pattern Dan Sommers <dan@tombstonezero.net> - 2013-05-10 06:22 +0000
                      Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-10 11:00 +0000
                        Re: object.enable() anti-pattern Robert Kern <robert.kern@gmail.com> - 2013-05-10 13:19 +0100
                          Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-10 10:01 -0400
                            Re: object.enable() anti-pattern Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-05-10 15:29 +0100
                              Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-10 10:37 -0400
                                Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-11 00:46 +1000
                                  Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-10 10:54 -0400
                                    Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-11 01:09 +1000
                                      Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-10 11:21 -0400
                                        Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-11 01:44 +1000
                            Re: object.enable() anti-pattern Robert Kern <robert.kern@gmail.com> - 2013-05-10 16:33 +0100
                        Re: object.enable() anti-pattern Serhiy Storchaka <storchaka@gmail.com> - 2013-05-10 18:44 +0300
                          Re: object.enable() anti-pattern André Malo <ndparker@gmail.com> - 2013-05-11 17:33 +0200
                            Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-12 02:04 +1000
                        Re: object.enable() anti-pattern Robert Kern <robert.kern@gmail.com> - 2013-05-10 18:20 +0100
                          Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-11 07:51 +0000
                            Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-11 09:31 -0400
                            Re: object.enable() anti-pattern Robert Kern <robert.kern@gmail.com> - 2013-05-11 20:55 +0100
                            Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-12 08:39 +1000
                        Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-11 03:24 +1000
                        Re: object.enable() anti-pattern Mark Janssen <dreamingforward@gmail.com> - 2013-05-10 19:43 -0700
                        Re: object.enable() anti-pattern Wayne Werner <wayne@waynewerner.com> - 2013-05-12 11:48 -0500
                        Re: object.enable() anti-pattern Terry Jan Reedy <tjreedy@udel.edu> - 2013-05-12 16:23 -0400
                  Re: object.enable() anti-pattern Mark Janssen <dreamingforward@gmail.com> - 2013-05-09 20:51 -0700
                Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-10 13:08 +1000
            Re: object.enable() anti-pattern roy@panix.com (Roy Smith) - 2013-05-09 14:59 -0400
              Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-10 07:55 +1000
        Re: object.enable() anti-pattern Nobody <nobody@nowhere.com> - 2013-05-10 17:59 +0100
          Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-10 13:32 -0400
            Re: object.enable() anti-pattern Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-05-11 15:24 -0400
          Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-11 07:05 +0000
    Re: object.enable() anti-pattern Mark Janssen <dreamingforward@gmail.com> - 2013-05-08 19:53 -0700
    Re: object.enable() anti-pattern Mark Janssen <dreamingforward@gmail.com> - 2013-05-08 19:56 -0700
    Re: object.enable() anti-pattern Wayne Werner <wayne@waynewerner.com> - 2013-05-09 06:08 -0500
      Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-09 11:51 +0000
      Re: object.enable() anti-pattern Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2013-05-10 11:43 +1200
        Re: object.enable() anti-pattern Michael Speer <knomenet@gmail.com> - 2013-05-09 20:18 -0400
          Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-09 20:50 -0400
        Re: object.enable() anti-pattern Wayne Werner <wayne@waynewerner.com> - 2013-05-12 12:14 -0500
        Re: object.enable() anti-pattern Terry Jan Reedy <tjreedy@udel.edu> - 2013-05-12 16:03 -0400
        Re: object.enable() anti-pattern Greg Ewing <greg.ewing@canterbury.ac.nz> - 2013-05-13 11:18 +1200
        Re: object.enable() anti-pattern Fábio Santos <fabiosantosart@gmail.com> - 2013-05-13 07:32 +0100
        Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-13 17:36 +1000
        Re: object.enable() anti-pattern Fábio Santos <fabiosantosart@gmail.com> - 2013-05-13 09:09 +0100
        Re: object.enable() anti-pattern Wayne Werner <wayne@waynewerner.com> - 2013-05-13 08:15 -0500

Page 2 of 5 — ← Prev page 1 [2] 3 4 5  Next page →


#45097

FromRoy Smith <roy@panix.com>
Date2013-05-10 09:22 -0400
Message-ID<roy-85A979.09223110052013@news.panix.com>
In reply to#45090
In article <518cc239$0$29997$c3e8da3$5496439d@news.astraweb.com>,
 Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:

> > int fd = 37;
> > 
> > I've just created a file descriptor.  There is not enough information
> > given to know if it corresponds to an open file or not.
> 
> No, you haven't created a file descriptor. You've made up a number which 
> C will allow you to use as an index into the file descriptor table, 
> because C is a high-level assembler with very little in the way of type 
> safety, and what little there is you can normally bypass.

No, I've created a file descriptor, which is, by definition, an integer. 
It has nothing to do with C.  This is all defined by the POSIX 
interface.  For example, the getdtablesize(2) man page says:

"The entries in the descriptor table are numbered with small integers 
starting at 0.  The call getdtablesize() returns the size of this table."

So, I am now guaranteed that fds will be ints.  I also know the 
guaranteed minimum and maximum values.

The system even makes certain guarantees which let me predict what file 
descriptor I'll get next in certain situations.  For example, from the 
dup(2) page on my OSX box:

"The new descriptor returned by the call is the lowest numbered 
descriptor currently not in use by the process."

> What you haven't done is create the record in the file descriptor table.

That's correct.  But, as described above, the system makes certain 
guarantees which allow me to reason about the existence or non-existence 
os such entries.

> You can't expect that read(fd) or write(fd) will work

I can expect that they will work if I have reasoned correctly about the 
POSIX-guaranteed semantics.  For example, POSIX says(*) that this C 
program is guaranteed to print, "hello, fd world" (assuming the 
assertion passes):

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

int main(int argc, char** argv) {
    int max_files = getdtablesize();
    assert(max_files >= 4);

    for (int i = 3; i < max_files; ++i) {
        close(i);
    }

    dup(2);
    char* message = "hello, fd world\n";
    write(3, message, strlen(message));
}

> What you've done is the moral equivalent of choosing an integer at 
> random, coercing it to a pointer, then dereferencing it to peek or poke 
> at some memory address. (Although fortunately much safer.)

No, what I've done is taken advantage of behaviors which are guaranteed 
by POSIX.

But, we're going off into the weeds here.  Where this started was you 
said:

> There is no sensible use-case for creating a file WITHOUT OPENING
> it. What would be the point?

I agree with you, in general, that it is usually poor design to have 
classes which require instances to be initialized after they are created.

The problem is, you chose as your example a particular domain where the 
underlying objects being modeled have unusual semantics imposed by an 
interface that's 40 years old.  And then you made absolute statements 
about there not possibly ever being certain use cases, when clearly 
there are (for that domain).

-----------------------
(*) Technically, getdtablesize() isn't POSIX, but POSIX does define 
other ways to get the same information.

[toc] | [prev] | [next] | [standalone]


#45122

FromCameron Simpson <cs@zip.com.au>
Date2013-05-11 08:25 +1000
Message-ID<mailman.1544.1368224768.3114.python-list@python.org>
In reply to#45097
On 10May2013 09:22, Roy Smith <roy@panix.com> wrote:
| In article <518cc239$0$29997$c3e8da3$5496439d@news.astraweb.com>,
|  Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:
| > > int fd = 37;
| > > 
| > > I've just created a file descriptor.  There is not enough information
| > > given to know if it corresponds to an open file or not.
| > 
| > No, you haven't created a file descriptor. You've made up a number which 
| > C will allow you to use as an index into the file descriptor table, 
| > because C is a high-level assembler with very little in the way of type 
| > safety, and what little there is you can normally bypass.
| 
| No, I've created a file descriptor, which is, by definition, an integer. 
| It has nothing to do with C.  This is all defined by the POSIX 
| interface.  For example, the getdtablesize(2) man page says:
| 
| "The entries in the descriptor table are numbered with small integers 
| starting at 0.  The call getdtablesize() returns the size of this table."
[... snip ...]

I'm with Steven here.

You've made a number that can be used with calls that access the
OS file descriptor table. But it isn't a file descriptor. (Yes, the
in-program number is just a number either way.)

The descriptor table is an in-kernel data structure, filled with
file descriptors. All you have is a label that may or may not access
a file descriptor.

Anyway, we all know _what_ goes on. We're just having terminology issues.

Cheers,
-- 
Cameron Simpson <cs@zip.com.au>

My computer always does exactly what I tell it to do but sometimes I have
trouble finding out what it was that I told it to do.
        - Dick Wexelblat <rlw@ida.org>

[toc] | [prev] | [next] | [standalone]


#45124

FromMark Janssen <dreamingforward@gmail.com>
Date2013-05-10 20:16 -0700
Message-ID<mailman.1546.1368242179.3114.python-list@python.org>
In reply to#45097
> | No, I've created a file descriptor, which is, by definition, an integer.
> | It has nothing to do with C.  This is all defined by the POSIX
> | interface.  For example, the getdtablesize(2) man page says:
> |
> | "The entries in the descriptor table are numbered with small integers
> | starting at 0.  The call getdtablesize() returns the size of this table."
> [... snip ...]
>
> I'm with Steven here.
>
> You've made a number that can be used with calls that access the
> OS file descriptor table. But it isn't a file descriptor. (Yes, the
> in-program number is just a number either way.)

Steven, don't be misled.  POSIX is not the model to look to -- it does
not acknowledge that files are actual objects that reside on a piece
of hardware.  It is not simply an integer.

Mark

[toc] | [prev] | [next] | [standalone]


#45125

FromThomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de>
Date2013-05-11 06:21 +0200
Message-ID<kmkh0p$oe0$1@r01.glglgl.de>
In reply to#45097
Am 10.05.2013 15:22 schrieb Roy Smith:

> That's correct.  But, as described above, the system makes certain
> guarantees which allow me to reason about the existence or non-existence
> os such entries.

Nevertheless, your 37 is not a FD yet.

Let's take your program:

> #include <unistd.h>
> #include <stdio.h>
> #include <string.h>
> #include <assert.h>
>
> int main(int argc, char** argv) {
>      int max_files = getdtablesize();
>      assert(max_files >= 4);

Until here, the numbers 3 toll max_files may or may not be FDs.

>      for (int i = 3; i < max_files; ++i) {
>          close(i);
>      }

Now they are closed; they are definitely no longer FDs even if they 
were. If you would use them in a file operation, you'd get a EBADF which 
means "fd is not a valid file descriptor".

>      dup(2);


 From now on, 3 is a FD and you can use it as such.

>      char* message = "hello, fd world\n";
>      write(3, message, strlen(message));
> }
>

> No, what I've done is taken advantage of behaviors which are guaranteed
> by POSIX.

Maybe, but the integer numbers get or los their property as a file 
descriptor with open() and close() and not by assigning them to an int.


Thomas

[toc] | [prev] | [next] | [standalone]


#45131

FromMark Janssen <dreamingforward@gmail.com>
Date2013-05-10 21:00 -0700
Message-ID<mailman.1555.1368273954.3114.python-list@python.org>
In reply to#45097
> Steven, don't be misled.  POSIX is not the model to look to -- it does
> not acknowledge that files are actual objects that reside on a piece
> of hardware.  It is not simply an integer.

Please disregard this (my own) flame bait.
-- 
MarkJ
Tacoma, Washington

[toc] | [prev] | [next] | [standalone]


#45146

FromDennis Lee Bieber <wlfraed@ix.netcom.com>
Date2013-05-11 15:04 -0400
Message-ID<mailman.1560.1368299090.3114.python-list@python.org>
In reply to#45083
On 10 May 2013 05:00:53 GMT, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> declaimed the following in
gmane.comp.python.general:

> 
> But even if C allowed you to do so, doesn't mean that it is a good idea. 
> At least some variants of Pascal force you to do the following:
> 
> # Pseudo-code.
> f = open(filename)
> really_open(f)
> data = read(f)  # or write, or *any other operation at all*
> 
> Surely we can agree that having to call both open() and really_open() 
> before you get an actually opened file that you can use is one call too 
> many? There is *nothing* you can do with f before calling really_open(). 
> So why require it?
>
	Well... As I recall, original Pascal required all files to be named
on the command line invocation. There was no way to dynamically assign a
file name to a file object within the language.

{Looking at the 3rd Edition Jensen&Wirth confirms that -- even the ISO
standard Pascal does not have an internal way to link a filename to a
file variable.}

> (For the record, "really_open" is spelled "reset" or "rewrite" depending 
> on whether you want to read or write to the file.)

	So your example, the open could better be names "assign" or "link",
as it associates the name of the file with the file variable, but does
not do anything with the file system itself -- that would be the
standard Pascal reset/rewrite. 

	A concept that is probably an artifact of the mainframe operating
systems in those days. Linkage of a physical file to a languages
internal "file" concept tended to be done with job control language
surrounding the invocation of the program itself.
-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
        wlfraed@ix.netcom.com    HTTP://wlfraed.home.netcom.com/

[toc] | [prev] | [next] | [standalone]


#45061

FromGreg Ewing <greg.ewing@canterbury.ac.nz>
Date2013-05-10 10:56 +1200
Message-ID<mailman.1509.1368140219.3114.python-list@python.org>
In reply to#45014
Cameron Simpson wrote:
> You open a file with "0" modes, so
> that it is _immediately_ not writable. Other attempts to make the
> lock file thus fail because of the lack of write,

I don't think that's quite right. You open it with
O_CREAT+O_EXCL, which atomically fails if the file
already exists. The read/write modes don't really
come into it, as far as I know.

-- 
Greg

[toc] | [prev] | [next] | [standalone]


#45032

FromRoy Smith <roy@panix.com>
Date2013-05-09 09:07 -0400
Message-ID<roy-8428A6.09074209052013@news.panix.com>
In reply to#45002
In article <518b32ef$0$11120$c3e8da3@news.astraweb.com>,
 Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:
 
> There is no sensible use-case for creating a file without opening it.

Sure there is.  Sometimes just creating the name in the file system is 
all you want to do.  That's why, for example, the unix "touch" command 
exists.

[toc] | [prev] | [next] | [standalone]


#45034

FromOscar Benjamin <oscar.j.benjamin@gmail.com>
Date2013-05-09 14:51 +0100
Message-ID<mailman.1492.1368107499.3114.python-list@python.org>
In reply to#45032
On 9 May 2013 14:07, Roy Smith <roy@panix.com> wrote:
> In article <518b32ef$0$11120$c3e8da3@news.astraweb.com>,
>  Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:
>
>> There is no sensible use-case for creating a file without opening it.
>
> Sure there is.  Sometimes just creating the name in the file system is
> all you want to do.  That's why, for example, the unix "touch" command
> exists.

Wouldn't the code that implements the touch command just look
something like this:

f = open(filename)
f.close()

Or is there some other way of creating the file that doesn't open it
(I mean in general not just in Python)?


Oscar

[toc] | [prev] | [next] | [standalone]


#45051

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-09 18:21 +0000
Message-ID<518be931$0$29997$c3e8da3$5496439d@news.astraweb.com>
In reply to#45032
On Thu, 09 May 2013 09:07:42 -0400, Roy Smith wrote:

> In article <518b32ef$0$11120$c3e8da3@news.astraweb.com>,
>  Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:
>  
>> There is no sensible use-case for creating a file without opening it.
> 
> Sure there is.  Sometimes just creating the name in the file system is
> all you want to do.  That's why, for example, the unix "touch" command
> exists.

Since I neglected to make it clear above that I was still talking about 
file objects, rather than files on disk, I take responsibility for this 
misunderstanding. I thought that since I kept talking about file 
*objects* and *constructors*, people would understand that I was talking 
about in-memory objects rather than on-disk files. Mea culpa.

So, let me rephrase that sentence, and hopefully clear up any further 
misunderstandings.

There is no sensible use-case for creating a file OBJECT unless it 
initially wraps an open file pointer.

This principle doesn't just apply to OOP languages. The standard C I/O 
library doesn't support creating a file descriptor unless it is a file 
descriptor to an open file. open() has the semantics:

"It shall create an open file description that refers to a file and a 
file descriptor that refers to that open file description."

http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html

and there is no corresponding function to create a *closed* file 
description. (Because such a thing would be pointless.)

Of course language designers are free to design their language to work 
under whatever anti-patterns they desire. I quote from the Pascal 
Language Reference:

"open associates the permanent file file [sic] with a file variable for 
reading or writing. open does not actually open the file; you must call 
reset or rewrite before reading or writing to that file."

http://www.amath.unc.edu/sysadmin/DOC4.0/pascal/lang_ref/
ref_builtin.doc.html


but since that's not a part of standard Pascal, other Pascals may behave 
differently.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#45053

FromMRAB <python@mrabarnett.plus.com>
Date2013-05-09 19:34 +0100
Message-ID<mailman.1501.1368124461.3114.python-list@python.org>
In reply to#45051
On 09/05/2013 19:21, Steven D'Aprano wrote:
> On Thu, 09 May 2013 09:07:42 -0400, Roy Smith wrote:
>
>> In article <518b32ef$0$11120$c3e8da3@news.astraweb.com>,
>>  Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:
>>
>>> There is no sensible use-case for creating a file without opening it.
>>
>> Sure there is.  Sometimes just creating the name in the file system is
>> all you want to do.  That's why, for example, the unix "touch" command
>> exists.
>
> Since I neglected to make it clear above that I was still talking about
> file objects, rather than files on disk, I take responsibility for this
> misunderstanding. I thought that since I kept talking about file
> *objects* and *constructors*, people would understand that I was talking
> about in-memory objects rather than on-disk files. Mea culpa.
>
> So, let me rephrase that sentence, and hopefully clear up any further
> misunderstandings.
>
> There is no sensible use-case for creating a file OBJECT unless it
> initially wraps an open file pointer.
>
You might want to do this:

f = File(path)
if f.exists():
     ...

This would be an alternative to:

if os.path.exists(path):
     ...

> This principle doesn't just apply to OOP languages. The standard C I/O
> library doesn't support creating a file descriptor unless it is a file
> descriptor to an open file. open() has the semantics:
>
> "It shall create an open file description that refers to a file and a
> file descriptor that refers to that open file description."
>
> http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html
>
> and there is no corresponding function to create a *closed* file
> description. (Because such a thing would be pointless.)
>
[snip]

[toc] | [prev] | [next] | [standalone]


#45073

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-10 02:30 +0000
Message-ID<518c5bbc$0$29997$c3e8da3$5496439d@news.astraweb.com>
In reply to#45053
On Thu, 09 May 2013 19:34:25 +0100, MRAB wrote:

>> There is no sensible use-case for creating a file OBJECT unless it
>> initially wraps an open file pointer.
>>
> You might want to do this:
> 
> f = File(path)
> if f.exists():
>      ...
> 
> This would be an alternative to:
> 
> if os.path.exists(path):
>      ...

Sure, but your made-up File object does not represent a file, it 
represents a pathname which *may or may not* exist. Pathnames are not 
files. Not all files have a pathname that refers to them, and not all 
pathnames point to an actual file. Since it has an exists() method that 
can return False, there are so-called "File" objects that aren't files 
and the name is a misnomer. A much better name for the class would be 
"Path", not "File".

I'm not saying that there is never a use-case for some objects to have an 
"enable" or "start" or "open" method. That would clearly be a silly thing 
to say. In the real world, we design many objects to have a start switch. 
It would be pretty horrible if your car was running all the time. But 
that's because there are actual use-cases for having cars *not* run, and 
"make it stop" is the safe default behaviour.

Your fridge, on the other hand, doesn't have a "make it go" button. So 
long as power is applied to it, your fridge automatically runs. Likewise, 
your watch is an "always on" device, provided it hasn't wound down or 
have a flat battery. Your fire alarm is "always on". 

I must admit I am astonished at how controversial the opinion "if your 
object is useless until you call 'start', you should automatically call 
'start' when the object is created" has turned out to be.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#45075

FromRoy Smith <roy@panix.com>
Date2013-05-09 23:09 -0400
Message-ID<roy-6D8B98.23095509052013@news.panix.com>
In reply to#45073
In article <518c5bbc$0$29997$c3e8da3$5496439d@news.astraweb.com>,
 Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:

> I must admit I am astonished at how controversial the opinion "if your 
> object is useless until you call 'start', you should automatically call 
> 'start' when the object is created" has turned out to be.

I'm sorry.  I thought you were here for an argument.

I think where things went pear shaped is when you made the statement:

>> There is no sensible use-case for creating a file OBJECT unless it
>> initially wraps an open file pointer.

That's a pretty absolute point of view.  Life is rarely so absolute.

[toc] | [prev] | [next] | [standalone]


#45079

FromMark Janssen <dreamingforward@gmail.com>
Date2013-05-09 20:19 -0700
Message-ID<mailman.1520.1368155947.3114.python-list@python.org>
In reply to#45075
> I think where things went pear shaped is when you made the statement:
>
>>> There is no sensible use-case for creating a file OBJECT unless it
>>> initially wraps an open file pointer.
>
> That's a pretty absolute point of view.  Life is rarely so absolute.

In the old days, it was useful to have fine-grained control over the
file object because you didn't know where it might fail, and the OS
didn't necessarily give you give good status codes.  So being able to
step through the entire process was the job of the progammers.

Now, with languages so high like python and hardware so common, it
almost is never necessary, so he has some point.   A closed file
pointer is useful from a OS-progamming point-of-view though because
you generally never want to leave files open where they'd block other
I/O.


-- 
MarkJ
Tacoma, Washington

[toc] | [prev] | [next] | [standalone]


#45080

FromChris Angelico <rosuav@gmail.com>
Date2013-05-10 13:46 +1000
Message-ID<mailman.1521.1368157593.3114.python-list@python.org>
In reply to#45075
On Fri, May 10, 2013 at 1:19 PM, Mark Janssen <dreamingforward@gmail.com> wrote:
>> I think where things went pear shaped is when you made the statement:
>>
>>>> There is no sensible use-case for creating a file OBJECT unless it
>>>> initially wraps an open file pointer.
>>
>> That's a pretty absolute point of view.  Life is rarely so absolute.
>
> In the old days, it was useful to have fine-grained control over the
> file object because you didn't know where it might fail, and the OS
> didn't necessarily give you give good status codes.  So being able to
> step through the entire process was the job of the progammers.

I don't know what you mean by the "old days", but a couple of decades
ago, there were no such things as "file objects". You call a function
to open a file, you get back a number. You explicitly close that by
calling another function and passing it that number. In fact, there is
no way to have a "file object" that doesn't have an open file
associated with it, because it's simply... a number.

> Now, with languages so high like python and hardware so common, it
> almost is never necessary, so he has some point.   A closed file
> pointer is useful from a OS-progamming point-of-view though because
> you generally never want to leave files open where they'd block other
> I/O.

I'm beginning to wonder if you and Dihedral are swapping notes.
Dihedral's been sounding fairly coherent lately.

ChrisA

[toc] | [prev] | [next] | [standalone]


#45084

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-10 05:03 +0000
Message-ID<518c7f8e$0$29997$c3e8da3$5496439d@news.astraweb.com>
In reply to#45075
On Thu, 09 May 2013 23:09:55 -0400, Roy Smith wrote:

> In article <518c5bbc$0$29997$c3e8da3$5496439d@news.astraweb.com>,
>  Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:
> 
>> I must admit I am astonished at how controversial the opinion "if your
>> object is useless until you call 'start', you should automatically call
>> 'start' when the object is created" has turned out to be.
> 
> I'm sorry.  I thought you were here for an argument.

No, I'm here for the abuse.


> I think where things went pear shaped is when you made the statement:
> 
>>> There is no sensible use-case for creating a file OBJECT unless it
>>> initially wraps an open file pointer.
> 
> That's a pretty absolute point of view.  Life is rarely so absolute.

So far the only counter-examples given aren't counter-examples. One 
involves opening the file. The other involves something which isn't a 
file, but a string instead. If there are any counter-examples, they are 
impossible in Python and C: you cannot create a file object in Python 
without opening it, and you cannot create a file descriptor in C without 
opening it. But not in Pascal, which actually supports my claim that this 
is an anti-pattern: while some Pascal implementations do allow you to 
create a non-open file, you cannot do *anything* with it until you open 
it, except generate bugs.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#45086

FromDan Sommers <dan@tombstonezero.net>
Date2013-05-10 06:22 +0000
Message-ID<Hm0jt.6$I26.5@newsfe26.iad>
In reply to#45084
On Fri, 10 May 2013 05:03:10 +0000, Steven D'Aprano wrote:

>>>> There is no sensible use-case for creating a file OBJECT unless it
>>>> initially wraps an open file pointer.

> So far the only counter-examples given aren't counter-examples ...

Well, sure, if you discount operations like "create this file" and
queries like "could I delete this file if I wanted to?" [0] as methods
of the file system rather than of a hypothetical file object.

What about a distributed system?  Suppose I want to create a file object
in one place, and send that object to the another place for the file to
be read from or written to [1]?  Suppose that for security reasons, I
have to do it that way, because the first place can only create the
objects, and the second place can only access the underly file contents
through an existing object?

I suppose that this case exists even in a non-distributed system that
allows whatever execution unit exists to change its own security
settings (POSIX has setuid and setgid functions), or exposes file ACLs
as methods of file objects rather than of the OS or file system.

What, exactly, does a "file object" represent?

And going back to your original comment (which was actually in response
to one of my posts), at least some operations on python file objects
*could* succeed without having to open the file.  An OS could provide
truncate, or writeable, on un-opened files; and certainly Python could
provide encoding, or isatty, on un-opened files.  Of these, truncate
might be the closest use case of creating a file object without any
intent to write to it, for some definition of "write to it."

Dan

[0] Yes, I understand that asking first instead of trying to delete the
file is just asking to lose any number of potential race conditions,
assuming that your system even supports race conditions.

[1] Think about a multi-threaded (or otherwise distributed) FTP or HTTP
server.  No, don't think about the server vs. the client, but rather a
"core" server overseeing "sub" servers for different sessions.

[toc] | [prev] | [next] | [standalone]


#45092

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-05-10 11:00 +0000
Message-ID<518cd360$0$29997$c3e8da3$5496439d@news.astraweb.com>
In reply to#45086
On Fri, 10 May 2013 06:22:31 +0000, Dan Sommers wrote:

> On Fri, 10 May 2013 05:03:10 +0000, Steven D'Aprano wrote:
> 
>>>>> There is no sensible use-case for creating a file OBJECT unless it
>>>>> initially wraps an open file pointer.
> 
>> So far the only counter-examples given aren't counter-examples ...
> 
> Well, sure, if you discount operations like "create this file" and
> queries like "could I delete this file if I wanted to?" [0] as methods
> of the file system rather than of a hypothetical file object.
> 
> What about a distributed system?  Suppose I want to create a file object
> in one place, and send that object to the another place for the file to
> be read from or written to [1]?  Suppose that for security reasons, I
> have to do it that way, because the first place can only create the
> objects, and the second place can only access the underly file contents
> through an existing object?

Unless you have re-implemented the file I/O system, it doesn't matter. If 
your file objects are based on C I/O, then even if the first server 
cannot read or write to the files it still creates file objects in an 
open state, because that is how C works.

Or maybe the first server only creates some sort of proxy to the real 
underlying file object. Or maybe you're re-implemented the I/O system, 
and aren't following C's design. Since you're just making this up as a 
thought experiment, anything is possible.

But either way, that's fine. You've found an object where it does make 
sense to have an explicit "make it go" method: first one entity has 
permission to construct the object, but not to open the underlying file. 
Another entity has permission to open the underlying file, but not to 
create the object. I have no idea whether this is a reasonable security 
design or not, it actually sounds a bit rubbish to me but what do I know? 
So let's treat it as a reasonable design. 

As I've said, repeatedly, that's not what I'm talking about.

When you DON'T have useful things that can be done with the object before 
calling "enable", then it is an anti-pattern to require a separate call 
to "enable" method, and the enable functionality should be moved into the 
object constructor. If you DO have useful things that can be done, like 
pass the object to another entity, for security, then that's a whole 
'nuther story.

Really, what I'm describing is *normal* behaviour for most objects. We 
don't usually design APIs like this:

n = int("42")
n.enable()
m = n + 1
m.enable()
x = m*2 + n*3
print x - 1  # oops, raises because I forgot to call x.enable()

That's a rubbish API, and for simple data-like objects, we all agree it 
is a rubbish API. So why accept the same rubbish API just because the 
object is more complicated? If you don't have a good, reasonable, non-
contrived use-case for a separate "make it go" method, don't use one.


For my next controversial opinion, I'm going to argue that we should do 
arithmetic using numbers rather than by inserting lists inside other 
lists:

# Do this:

count = 0
count += 1

# Not this:

count = []
count.insert(0, [])


*wink*


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#45093

FromRobert Kern <robert.kern@gmail.com>
Date2013-05-10 13:19 +0100
Message-ID<mailman.1527.1368188358.3114.python-list@python.org>
In reply to#45092
On 2013-05-10 12:00, Steven D'Aprano wrote:

> But either way, that's fine. You've found an object where it does make
> sense to have an explicit "make it go" method: first one entity has
> permission to construct the object, but not to open the underlying file.
> Another entity has permission to open the underlying file, but not to
> create the object. I have no idea whether this is a reasonable security
> design or not, it actually sounds a bit rubbish to me but what do I know?
> So let's treat it as a reasonable design.
>
> As I've said, repeatedly, that's not what I'm talking about.
>
> When you DON'T have useful things that can be done with the object before
> calling "enable", then it is an anti-pattern to require a separate call
> to "enable" method, and the enable functionality should be moved into the
> object constructor. If you DO have useful things that can be done, like
> pass the object to another entity, for security, then that's a whole
> 'nuther story.

I'd be curious to see in-the-wild instances of the anti-pattern that you are 
talking about, then. I think everyone agrees that entirely unmotivated "enable" 
methods should be avoided, but I have my doubts that they come up very often. Do 
programmers have a natural tendency to make an extra, completely unnecessary 
method? I would think that they have a natural tendency to the opposite.

In my experience, everyone has a reason in mind when they follow a 
pattern/anti-pattern. It is pretty rare that someone just does some specific, 
nameable thing for no reason at all. There is no need to call out an 
anti-pattern for which no one has a reason to do it. But there is a continuum of 
reasons. Some reasons are better than others. Some reasons only apply in a small 
set of circumstances but seem like they would apply more generally, at least to 
novice programmers. Programmers can be wrong about what they think the 
(anti-)pattern actually achieves. The whole point of naming an anti-pattern is 
to discuss those reasons, show where they are misapplied, where YAGNI, why 
novices overuse it, other patterns that should be used instead, and also the 
circumstances where it is actually a good pattern instead.

To artificially limit the discussion of the anti-pattern to the trivial, 
entirely unmotivated case forbids most of the interesting and instructive parts 
of the conversation.

-- 
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
  that is made terrible by our own mad attempt to interpret it as though it had
  an underlying truth."
   -- Umberto Eco

[toc] | [prev] | [next] | [standalone]


#45098

FromRoy Smith <roy@panix.com>
Date2013-05-10 10:01 -0400
Message-ID<roy-F6FC44.10011410052013@news.panix.com>
In reply to#45093
In article <mailman.1527.1368188358.3114.python-list@python.org>,
 Robert Kern <robert.kern@gmail.com> wrote:

> I'd be curious to see in-the-wild instances of the anti-pattern that 
> you are talking about, then. I think everyone agrees that entirely 
> unmotivated "enable" methods should be avoided, but I have my doubts 
> that they come up very often. 

As I mentioned earlier in this thread, this was a common pattern in the 
early days of C++, when exceptions were a new concept and handled poorly 
by many compilers (and, for that matter, programmers).

There was a school of thought that constructors should never be able to 
fail (because the only way for a constructor to fail is to throw an 
exception).  The pattern was to always have the constructor succeed, and 
then either have a way to check to see if the newly-constructed object 
was valid, or have a separate post-construction initialization step 
which could fail.

See, for example, the isValid() and Exists() calls for RogueWave's 
RWFile class (http://tinyurl.com/c8kv26g).  And also, 
http://tinyurl.com/cgs6clx.

Even today, there are C++ implementations which do not use exceptions.  
Some are for use in embedded or real-time systems where things need to 
be strictly time-bound and/or memory-bound.  Others are for historical 
reasons (http://tinyurl.com/6hn4zo).

Once people were used to writing "can't fail" constructors in C++, they 
often continued using that pattern in other languages, where the 
underlying reasons no longer made sense.  Quite possibly, they never 
even knew the underlying reasons; they were taught, "Constructors must 
never fail", and assumed it was a universal rule.

This, BTW, is one of my biggest beefs with the classic Gang Of Four 
pattern book.  It presents a bunch of patterns as being universally 
applicable, when in reality many (if not most) of them are highly C++ 
specific.

BTW, whenever I read things like, "I think everyone agrees", I 
automatically assume what the writer really meant was, "I, and all the 
people who agree with me, think".

[toc] | [prev] | [next] | [standalone]


Page 2 of 5 — ← Prev page 1 [2] 3 4 5  Next page →

Back to top | Article view | comp.lang.python


csiph-web