I will never, ever, ever possibly begin to process all this mail.
It's completely impossible.  I have three days before I leave the
country for three weeks, and nothing is done.  Therefore, my answer
to you will be short and underdone.  One can type on p6 lists *all*
day and get no nearer to closure or clarity on anything.  Especially
the ratio of many-to-one will kill you.  I'm sure I could spend all 
day teaching you about filehandles and globs and OO and Perl. But I 
don't have that time. I'll give you pointers, and you'll have to 
teach yourself.

>> >       * Have to use ugly globref syntax to pass them around reliably.
>> No, you don't.  You can use globs.   But only if you don't have
>> prototypes, like sub opt(*).

>I would argue that many Perlers don't use prototypes.
>Whether they should or not is another issue, but prototypes
>are optional, and I believe they aren't useful in "named argument"
>cases like this anyway:

>       $foo->output(Verbose => 1,
>                    Formatter => $fmt,            
>                    Output => \*MYFILE,
>                    Errors => \*STDERR);

Again, the backslash is unneeded.

>> >       * Not first-class objects, so you can't subclass them.
>> 
>> That's not a good argument.  I can't subclass a number, either, nor
>> a function or format for that matter.

>It is a good argument when you consider how useful it is to be
>able to subclass an output handle.  Look at all the IO:: classes;
>if they weren't useful (at least, in the eyes of some people), 
>we wouldn't have them.  

Non-sequitur: just because something exist doesn't mean it's useful.
There's no need for most of them, and most are just lies.  The
select stuff is useful, and so too is the socket stuff.  The rest
is smoke and mirrors, mostly prevaricatory and deceptive.

>Subclassing is a means of extending or modifying the behavior
>of an existing abstract data type in a simple, strightforward way.
>It's well understood.  If we want to support output-handles with
>different kinds of behavior (and, as the author of IO::Scalar,
>I think that we do :-) ), then I argue that we should do so in
>an object-oriented fashion.

>> But what do you mean you can't subclass them?  

>Here's an excerpt from the IO::Handle documentation:

>  BUGS
>     Due to backwards compatibility, all filehandles resemble
>     objects of class IO::Handle, or actually classes derived
>     from that class.  They actually aren't.  Which means you
>     can't derive your own class from IO::Handle and inherit
>     those methods.

>Gosh darn it, what if I *want* to derive my own class from
>IO::Handle and inherit those methods?  And notice that Graham
>is listing this incapability as a BUG.  I agree with him.

This is misleading in the extreme, at best poorly documented.  You
are certainly capable of deriving from that class.  Here's the
empty subclass test:

    package FH_Empty;
    use strict;
    require FileHandle;
    our @ISA = qw/FileHandle/;
    1;

And here's the demo:

    use FH_Empty;
    ($it = FH_Empty->new)->open("> /dev/tty");
    $it->autoflush(1);
    $it->print("ready...");
    sleep 1;
    $it->print("...steady...");
    sleep 1;
    $it->print("go\n");

When run, it works just fine.  

What that confusing text you cited is alluding to can be seen 
in the following longer demo.  Consider this module:

    package Handle_Counter;

    use strict;

    use Exporter;
    our @ISA    = qw/Exporter/;
    our @EXPORT = qw/makefh/;

    use Symbol    qw/qualify_to_ref/;

    sub _genob {
        my ($invocant, $fh) = @_;
        return bless my $self = {
            HANDLE => $fh,
            COUNT  => 0,
        } => ref($invocant) || $invocant;
    } 

    sub makefh(;*) {
        my $whatever;
        if (@_) {
            $whatever = shift;
        } else {
            select($whatever = select(STDOUT));
        } 
        my $handle = qualify_to_ref($whatever, caller);
        return __PACKAGE__ -> _genob($handle);
    } 

    sub print {
        my $self = shift;
        my $n = ++$self->{COUNT};
        print { $self->{HANDLE} } "COUNT=$n @_\n";
    } 

    1;

Now, here's its demo:

    use strict;
    use Handle_Counter;
    my $fh = makefh();
    print "Got $fh\n";
    $fh->print("stuff");
    $fh->print("more stuff");
    $fh->print("and still more stuff");
    print $fh "bad stuff\n";

Which when run, produces:

    Got Handle_Counter=HASH(0xa9150)
    COUNT=1 stuff
    COUNT=2 more stuff
    COUNT=3 and still more stuff
    Not a GLOB reference at /tmp/demo2 line 13.

The issue is that you cannot make Perl's built-in print() operator
get at its indirect object's print() method if you unless you use
arrow syntax.  You can't use the indirect object syntax, because
print() is not overridable in this way.

Of course, it *is* overridable in *another* way.  Go back to
Handle_Counter.pm and add these:

    sub PRINT {
        my $self = shift;
        my $n = ++$self->{COUNT};
        print { $self->{HANDLE} } "COUNT=$n @_\n";
    }

    sub TIEHANDLE {
        my $class = shift;
        return &makefh;
    }

Now your demo of:

    tie *COUNT, Handle_Counter::, *STDOUT;
    print COUNT "bad stuff\n";

will in fact get it.

Oh, but you *ALSO* want 

    COUNT->print("bad stuff\n");

to work?  Well, you can do that, too; I leave this as
an exercise for the non-lwall reader. :-)

>> And what pray tell is
>> a "first class object"?  Please define "first class".

>I would want filehandles to be governed by the same rules as 
>any user-defined object: e.g., I want to be able to
>use method invocation in the same manner, I want to be able
>to create subclasses, and I want to be able to inspect
>instance variables.

It's not the filehandles' fault.  It's the way print() etc 
work.  To get what you want requires all I/O to be slowed
down a great deal (10x or worse), which is doubtless unacceptable.

>In other words, I don't want sentences like that snippet from
>IO::Handle above.

First you need to understand that snippet.

> 
>> >       * Special syntax to reassign STDOUT, instead of just $STDOUT = $foo.
>> 
>> What do you mean by "reassign to standard output"?  Do you mean
>> that file descriptor #1 should be pointing to a new place?

>> What are you thinking that this
>> mythical assignment should be doing?

>The same as any conventional assignment: to replace the object
>that represents the standard-output channel (*not* fd 1) with 
>one of my own choosing.  

Apparently you and I have differing notions of the definition of
"standard output".  It is *BY DEFINITION* file descriptor number one.
There is no "standard-output channel" held by a program that cannot
be maniupulated by 

    $ proggie 1>/tmp/file


>So that if someone has provided a CPAN
>module with this mythical Perl6 snippet:

>       sub printheader { print $STDOUT "Content-type: text/html\r\n\r\n"; }

>I can replace $STDOUT with, say, an IO::Scalar which routes
>all output to core:

>       $STDOUT = new IO::Scalar \$data;
>       printheader();
>       ### the header is now in $data

That's a completely different issue.  See above.   And go use
the insanely slow syntax.  Anybody who uses IOwhatever is
obviously interested in things running as slowly as possible.

>> >       * Stupid "gensym" tricks to create unique names.
>> 
>> There is nothing "stupid" about using Symbol::gensym() to generate
>> unique symbols.  That is, after all, its purpose.

>I didn't say that gensym() was stupid. I implied that this was a
>bizzare way to create new filehandles.  

So don't do that.  Haven't I said this already?

>I much prefer:
>       $fh = new FileHandle;
>because this is familiar turf: you can show this to any novice
>developer with a smattering of OO, and even if they don't know
>what FileHandle is, they have a pretty good idea that a new
>instance of class FileHandle is being created and assigned
>to $fh.

I much prefer "my" or "local", thank you very much.

    local *FH;
    ...
    return *FH;

or even 

    my $fh;
    open($fh, ...);  # or socket() etc
    return $fh;


>IO::Handle uses gensym in its new() methods.  

Chalk it up to superstition, misunderstanding, and ancient code.
You certainly do not *need* to do this.

Oh, and on your little destructor thing, consider this from the Camel:

    sub FETCH {
        my $self  = shift;
        confess "I am not a class method" unless ref $self;
        return unless open my $fh, $$self;
        read($fh, my $value, -s $fh);  # NB: don't use -s on pipes!
        return $value;
    }

Look!  No fufi objecties, no destructors, no problems.

Is it, as you say,
>"unclear in the exteme" why IO::Handle is doing so?  It's clear
>to me: in order for IO::Handle to create a brand-new object, it
>must have a brand-new symbol because of Perl's underlying use
>of strings as means of discriminating i/o channels.

Underlying use of strings?  Hello?

I think not.

Again from Camel:

    sub TIEHANDLE {
        my $class = shift;
        my $form = shift;
        open my $self, $form, @_   or croak "can't open $form@_: $!";
        if ($form =~ />/) {
            print $self  "<SHOUT>\n";
            $$self->{WRITING} = 1;     # Remember to do end tag
        }
        return bless $self, $class;    # $self is a glob ref
    }

Underlying use of typeglobs, maybe.

>And all that I am saying is that this syntactic complication,
>this special case where "the filehandle name *is* the object",
>should be gotten rid of.  

That's not the problem.

    print $obj "whatever";

still doesn't do what you want.

>Unlike some other special Perl syntactic 
>constructs (e.g., regular expressions, "here-is" documents),
>the current filehandle syntax does not add anything of value to the 
>language, and yet it has caused a lot of confusion when new Perlers
>try to pass filehandles around between packages, and they don't
>yet know about globs.

>> >       * STDOUT->flush barfs if you don't "use FileHandle" first; sheesh.
>> 
>> Perl doesn't have built-in methods there: true.  Perhaps you
>> are proposing an implicit autoload?

>Actually, I'm proposing:

>       $STDOUT->flush

>with all that implies (if that means autoloading of IO::Handle, 
>then so be it).

IO::Handle is *TOO DAMNED BIG*.  Benchmark it.


>> I haven't yet seen anybody yet propose bifurcating {file,directory}handles.
>> This would certainly be nice.

>You mean, like a handle with a built-in "tee" capability?

No, and that's completely feasible.   See the Tie::Tee class in
Camel 3's tie chapter, or the sub tee forking open example in its
IPC chapter.

--tom

Reply via email to