>>>>>> 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.
You're missing one other case: if there's useful things that can be checked before calling enable(). Remember, on multi-user and/or multi-processing systems, there could be contention for a slow resource. If you automatically open a file for write, you're preventing everyone else from writing and potentially reading it. So there is something useful: did that file exist? Is that resource available for writing? Prior to such hi-level languages like Python and reliable hardware, such fine-grained control was important and vital. Now it can probably be relegated to special OS libraries. Mark > 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() Again, you only do that for shared resources. In this case, memory would have to be a (protected) shared resources, but the OS manages memory allocation, so it's not an issue. Mark > 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? I think I just told you, but let me know ..... :) > 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: Try arguing that we should have a common message-passing syntax. > # Do this: > > count = 0 > count += 1 > > # Not this: > > count = [] > count.insert(0, []) That's actually what they do in "set theory", believe it or not. MarkJ Tacoma, Washington -- http://mail.python.org/mailman/listinfo/python-list