Implementing Interfaces and Type Safety (OOP Newbie in Perl)

Discussion in 'Perl Misc' started by Veli-Pekka Tätilä, Aug 17, 2005.

  1. Hi,
    I'm new to OOP in Perl having only used classes by others, read some book's
    take on the subject and implemented closures for quick-n-dirty object-like
    thingies. One thing I didn't see mentioned in Beginning PErl is Perl's take
    on what Java calls interfaces and C++ programmers pure virtual abstract base
    classes. That is in stead of a real class with state or useful methods, it
    is something non-instanciable - a contract that concrete sub-classes will
    have a certain set of methods in them. Is there a good way to implement an
    interface in Perl or some perlish idiom for achieving the same thing?

    I've noticed that most Perl classes don't rely too much on abstraction where
    as in Java I'm almost always talking through some sort of interface. Don't
    get me wrong, though, usually I like Perl's simple and practical ways of
    achieving what you want, <grin>.

    Also, if there's such a thing as an interface in Perl, how is it used and
    what about type safety? In Java one would get a reference to the interface
    and can assign to it any class implementing the interface. Java will then
    automagically see that the right method gets called inside the class and we
    have polymorphism. Further more, type checking is done at compile time for
    the most part.

    From what I've understood objects are actually blessed references in Perl
    and when assigning to a reference, the type of the referent may vary freely.
    Thus the best you can do is to keep assigning the right sub-classes derived
    from a dummy interface class and hope that you don't make any mistakes in
    the process, right? The only trouble with that is accidentally assigning
    something that does not conform to the interface . Perl will only throw an
    error at compile time should the missing method or methods get called. I've
    noticed that even in trivial cases, typoed method names are not catched when
    checking the syntax. PHP 4 does come to mind, argh, but fortunately Perl's
    OOP stuff is not at all as toy-like as it used to be in PHP.

    In contrast, should one try using operators, functions or references with
    the wrong primitive type e.g. hash functions for arrays, you'll usually get
    at least a compile-time error before the app is run. is there any way of
    enforcing similar type safety for user-created objects?

    I suppose you could use reflection to some effect with the methods in the
    universal base class. Checking whether the referent is derived from the
    interface by calling isa or asking if it does support a particular method
    with the appropriately named method can.

    Is there a better way than reflection i.e. relying on prototypes or being
    able to strongly type references?

    Lastly, speaking of Perl's OOP stuff, I remember a funny quote about modules
    from the Camel book:

    <cite>
    Perl does not patrol private/public borders within its modules - unlike
    languages such as C++, Ada, and Modula-17, Perl isn't infatuated with
    enforced privacy. As we mentioned at the beginning of the chapter, a Perl
    module would prefer that you stayed out of its living room because you
    weren't invited, not because it has a shotgun.
    </cite>

    --
    With kind regards Veli-Pekka Tätilä ()
    Accessibility, game music, synthesizers and programming:
    http://www.student.oulu.fi/~vtatila/
     
    Veli-Pekka Tätilä, Aug 17, 2005
    #1
    1. Advertising

  2. Also sprach Veli-Pekka Tätilä:

    > I'm new to OOP in Perl having only used classes by others, read some book's
    > take on the subject and implemented closures for quick-n-dirty object-like
    > thingies. One thing I didn't see mentioned in Beginning PErl is Perl's take
    > on what Java calls interfaces and C++ programmers pure virtual abstract base
    > classes. That is in stead of a real class with state or useful methods, it
    > is something non-instanciable - a contract that concrete sub-classes will
    > have a certain set of methods in them. Is there a good way to implement an
    > interface in Perl or some perlish idiom for achieving the same thing?


    Yes, it can be simulated in a fairly simple manner. The idea is to write
    a package where each method dies on invocation. However, what you cannot
    easily have is compile-time checks that ensure that a class implementing
    that interface does in fact implement (=override in this case) all
    methods.

    Here is a simple interface:

    package Interface;

    use Carp;

    sub new {
    my $class = shift;
    croak "'$class' does not implement 'new'";
    }

    sub method1 {
    my $self = shift;
    my $class = ref $self;
    croak "'$class' does not implement 'method1'";
    }

    # etc.

    If you want to be smart and avoid typing repetitive code, have perl
    generate the methods for you based on a list of methods that must be
    implemented by subclasses:

    package Interface;

    use Carp;

    my @MUST_IMPLEMENT = qw/new method1 method2/;

    for (@MUST_IMPLEMENT) {
    no strict 'refs'; # when strictures are enabled
    *$_ = sub {
    my $invoc = shift;
    my $class = ref($invoc) || $invoc;
    croak "'$class' does not implement '$_'";
    };
    }
    1;
    __END__

    A class implementing the above interface would look like this:

    package Implementation;

    use base qw/Interface/; # subclass 'Interface'

    sub new {
    ...
    }
    sub method1 {
    ...
    }
    # etc.

    1;
    __END__


    > I've noticed that most Perl classes don't rely too much on abstraction where
    > as in Java I'm almost always talking through some sort of interface. Don't
    > get me wrong, though, usually I like Perl's simple and practical ways of
    > achieving what you want, <grin>.
    >
    > Also, if there's such a thing as an interface in Perl, how is it used and
    > what about type safety? In Java one would get a reference to the interface
    > and can assign to it any class implementing the interface. Java will then
    > automagically see that the right method gets called inside the class and we
    > have polymorphism. Further more, type checking is done at compile time for
    > the most part.


    When it comes to object-orientedness, everything happens at runtime as
    far as Perl is concerned. What you say about assigning an object to a
    variable of an interface type in Java (and the appropriate type checks
    at compile time) does not exist for Perl and I would assume there is no
    way to do it at compile-time. There are ways, however, to ensure no such
    assignments happens at run-time, but these need to be implemented
    manually, via a tied interface. But then this is quite heavy stuff.

    > From what I've understood objects are actually blessed references in Perl
    > and when assigning to a reference, the type of the referent may vary freely.
    > Thus the best you can do is to keep assigning the right sub-classes derived
    > from a dummy interface class and hope that you don't make any mistakes in
    > the process, right? The only trouble with that is accidentally assigning
    > something that does not conform to the interface . Perl will only throw an
    > error at compile time should the missing method or methods get called. I've
    > noticed that even in trivial cases, typoed method names are not catched when
    > checking the syntax. PHP 4 does come to mind, argh, but fortunately Perl's
    > OOP stuff is not at all as toy-like as it used to be in PHP.


    That is true. Mistyped method invocations are caught at runtime. They
    have to be due to Perl's super-polymorphic nature. Consider that a
    particular method might not exist at compile-time. It might be added
    later at run-time...alas, a whole class might suddenly spring into
    existance during run-time. Lack of compile-time checks is the price you
    have to pay when using a dynamic language such as Perl.

    > In contrast, should one try using operators, functions or references with
    > the wrong primitive type e.g. hash functions for arrays, you'll usually get
    > at least a compile-time error before the app is run. is there any way of
    > enforcing similar type safety for user-created objects?


    No. The reason why it works with functions is that functions don't have
    inheritance involved. No dynamic dispatch then means that many more
    things can be checked at compile-time. Note however that a mistyped
    function name is still a run-time error. The errors at compile-time that
    you mention are those concerning functions with a prototype:

    sub func (\@) {
    "I must receive an array";
    my $ary_ref = shift; # it's passed as reference
    }

    my @ary = (1 .. 10);
    func @ary; # ok

    func 1 .. 10; # compile-time error
    func $scalar; # as is this
    func %hash; # or this

    Perl-builtins have prototypes attached to them so there perl can make
    some sanity checks on the validity of the arguments at compile-time.

    > I suppose you could use reflection to some effect with the methods in the
    > universal base class. Checking whether the referent is derived from the
    > interface by calling isa or asking if it does support a particular method
    > with the appropriately named method can.


    Yes, this is what I referred to earlier with "but these need to be
    implemented manually". Run-time checks such as isa() or ref() are the
    ones most commonly found to catch type violations.

    > Is there a better way than reflection i.e. relying on prototypes or being
    > able to strongly type references?


    Prototypes don't exist for methods. Strongly typing references is
    possible to a certain limited extent. See 'perldoc fields'.

    > Lastly, speaking of Perl's OOP stuff, I remember a funny quote about modules
    > from the Camel book:
    >
    ><cite>
    > Perl does not patrol private/public borders within its modules - unlike
    > languages such as C++, Ada, and Modula-17, Perl isn't infatuated with
    > enforced privacy. As we mentioned at the beginning of the chapter, a Perl
    > module would prefer that you stayed out of its living room because you
    > weren't invited, not because it has a shotgun.
    ></cite>


    That's precisely what Perl is about. It's a matter of getting used to
    it. This very liberal approach may be frowned upon by the Ada language
    designers, however each has its own virtues and shortcomings. The
    non-enforced privacy in Perl doesn't exist because the designers of Perl
    were too dumb to implement it. It was a deliberate decision.

    Tassilo
    --
    use bigint;
    $n=71423350343770280161397026330337371139054411854220053437565440;
    $m=-8,;;$_=$n&(0xff)<<$m,,$_>>=$m,,print+chr,,while(($m+=8)<=200);
     
    Tassilo v. Parseval, Aug 17, 2005
    #2
    1. Advertising

  3. Re: Dynamic Typing, Defencive Programming and Prototypes (Was: Interfaces and Type Safety)

    Tassilo v. Parseval wrote:

    defencive programming:
    > So PHP is offensive. ;-)

    Yup, at least V4 is <smile>. But as to defencive programming in Perl, I've
    found these two lines invaluable:

    use strict;
    use warnings FATAL => qw|all|;

    Writing code with speech it is far too easy to accidentally mistype an
    identifier and try introducing a new variable in the middle of a
    print-statement or something. And as to making warnings die, it prevents you
    from fixing things lazily and catches subtle initialization bugs, very nice.
    Another benefit is knowing as soon as something goes wrong. As the screen
    reader's focus can be in one GUI widget at a time and the console app I'm
    doing runs in the background, dying quickly, forces me to actually notice
    the warnings. It would be even better if I could be warned audibly by
    emiting the bell char \a to the console when-ever this does happen. However,
    I reckon that's a no-can-do in Win32 as signals aren't implemented and END
    blocks not run when you die. Perhaps using eval, then.

    benefits of dynamic typing:
    > Consider a module that is used to write XML tags as generically as
    > possible. <snip> <snip> all you need is one special
    > method to handle it all. <snip> generate and compile
    > the requested method on the fly:

    I see, your auto load example is pretty impressive. Still, as they say
    there's more than one way to do it, wouldn't it be easier foor the caller if
    there was one createTag method whose first argument was the name of the tag.
    No auto-load or pollution of the callers namespace needed. But then again
    the other benefits you mentioned will be lost and you don't necessarily have
    to export the methods.

    ah, I think I now know another example of auto loading. The Win32::OLE
    module that I'm using a lot enables you to load in an OLE type library and
    after that the constructed object will magically have method and property
    names corresponding to those of the type library. And calling non-existant
    methods dies cleanly, too. I was really awed when I saw this. I cannot think
    of a way to achieve the same thing in Java, for instance, even if you could
    use reflection and polymorphism. Sure you might be able to have some
    dispatcher method whose first argument is the property or method being
    operated on, as in the previous example, but that doesn't look as smooth as
    in Perl. Finally, I'm greatful that Perl programmers generally don't do as
    much operator over-loading as C++-programmers, because it can be very
    confusing if overused.

    Prototypes:
    > Perl does have forward-declarations as well. The case above works if the
    > function definitions comes before the code that calls this function.

    I just tried your example and noticed the same thing on my own yesterday.
    Argh as in C again, I like the Java method where the compiler doesn't force
    you to type in the same thing twice for no obvious reasons: I mean obvious
    from the programmer convenience point of view.

    Anyway, what's the canonical way of including these protos? If I stick all
    of them at the beginning of the file, it is confusing for people reading it
    the first time. But then again I haven't seen people using C-like include
    files for definitions, either, and am unsure as to what extension such files
    should have. ph comes to mind standing for perl header.

    If I want to be truely lazy, is there a way of automatically copying the
    prototype from the implementation and placing it before the function is
    being used? I hope someone else has already done something like this and
    will search using PPM. Source filtering comes to mind as the first choice.

    --
    With kind regards Veli-Pekka Tätilä ()
    Accessibility, game music, synthesizers and programming:
    http://www.student.oulu.fi/~vtatila/
     
    Veli-Pekka Tätilä, Aug 19, 2005
    #3
  4. Re: Dynamic Typing, Defencive Programming and Prototypes (Was: Interfaces and Type Safety)

    Also sprach Veli-Pekka Tätilä:

    > Tassilo v. Parseval wrote:
    >
    > defencive programming:
    >> So PHP is offensive. ;-)

    > Yup, at least V4 is <smile>. But as to defencive programming in Perl, I've
    > found these two lines invaluable:
    >
    > use strict;
    > use warnings FATAL => qw|all|;
    >
    > Writing code with speech it is far too easy to accidentally mistype an
    > identifier and try introducing a new variable in the middle of a
    > print-statement or something. And as to making warnings die, it prevents you
    > from fixing things lazily and catches subtle initialization bugs, very nice.
    > Another benefit is knowing as soon as something goes wrong. As the screen
    > reader's focus can be in one GUI widget at a time and the console app I'm
    > doing runs in the background, dying quickly, forces me to actually notice
    > the warnings. It would be even better if I could be warned audibly by
    > emiting the bell char \a to the console when-ever this does happen. However,
    > I reckon that's a no-can-do in Win32 as signals aren't implemented and END
    > blocks not run when you die. Perhaps using eval, then.


    Don't the pseudo-signals __WARN__ and __DIE__ work on windows, too?
    With them:

    use warningsd FATAL => 'all';
    $SIG{ __DIE__ } = sub {
    for (1 .. 10) {
    print STDERR "\a"; # need auto-flushed handle here
    select undef, undef, undef, 0.2;
    }
    }

    Or use one of the Win32 modules to emmit this annoying "oh-oh" Windows
    system sound. :)

    > benefits of dynamic typing:
    >> Consider a module that is used to write XML tags as generically as
    >> possible. <snip> <snip> all you need is one special
    >> method to handle it all. <snip> generate and compile
    >> the requested method on the fly:

    > I see, your auto load example is pretty impressive. Still, as they say
    > there's more than one way to do it, wouldn't it be easier foor the caller if
    > there was one createTag method whose first argument was the name of the tag.
    > No auto-load or pollution of the callers namespace needed. But then again
    > the other benefits you mentioned will be lost and you don't necessarily have
    > to export the methods.


    Yes, having a createTag() method is how less dynamic languages would do
    it. With the expected consequences for the API.

    > ah, I think I now know another example of auto loading. The Win32::OLE
    > module that I'm using a lot enables you to load in an OLE type library and
    > after that the constructed object will magically have method and property
    > names corresponding to those of the type library. And calling non-existant
    > methods dies cleanly, too. I was really awed when I saw this. I cannot think
    > of a way to achieve the same thing in Java, for instance, even if you could
    > use reflection and polymorphism. Sure you might be able to have some
    > dispatcher method whose first argument is the property or method being
    > operated on, as in the previous example, but that doesn't look as smooth as
    > in Perl. Finally, I'm greatful that Perl programmers generally don't do as
    > much operator over-loading as C++-programmers, because it can be very
    > confusing if overused.


    Note that tied hashes or arrays are conceptually overloading the
    subscript operator. The C++ equivalent would be overloading the '[]'
    operator. So if you consider tying as overloading, then it is in fact
    common in Perl.

    However, Perl programmers seem to be less hooked on overloading
    operators the classical way (by using the 'overload' pragma).

    > Prototypes:
    >> Perl does have forward-declarations as well. The case above works if the
    >> function definitions comes before the code that calls this function.

    > I just tried your example and noticed the same thing on my own yesterday.
    > Argh as in C again, I like the Java method where the compiler doesn't force
    > you to type in the same thing twice for no obvious reasons: I mean obvious
    > from the programmer convenience point of view.


    The need for pre-declarations in certain languages has to do with the
    way the compilers are implemented. You need at least a two-phase
    compiler (that is, a compiler that makes two sweeps over the program or
    the intermediate internal representation of the program) to eliminate
    the need for forward declarations. However, there are also things like
    incremental compilation where it is crucial for the compiler to know the
    calling conventions for certain functions that are used in the code to
    be compiled but that are not yet defined.

    I reckon perl tries to reduce the number of visits of each syntax tree
    node as it increases compile-time. Forward-declarations are one way to
    ensure that prototypes can be checked at compile-time without the need
    of running through the abstract syntax tree too often.

    > Anyway, what's the canonical way of including these protos? If I stick all
    > of them at the beginning of the file, it is confusing for people reading it
    > the first time. But then again I haven't seen people using C-like include
    > files for definitions, either, and am unsure as to what extension such files
    > should have. ph comes to mind standing for perl header.


    Perl headers are already used for something else and they have .ph as
    extension. See 'perldoc h2ph'. It's fairly obscure.

    Just use .pm as extension which is also the only way that ensures you
    can include it with 'use'. If you want to indicate that a module only
    consists forward declaration use an appropriate naming scheme:

    Module_inc.pm # or Module_fwd.pm or so
    Module.pm

    Note that the file containing the forward declarations needs to be
    included at compile-time in order to have any effect. When you include
    modules via 'use', this happens anyway.

    > If I want to be truely lazy, is there a way of automatically copying the
    > prototype from the implementation and placing it before the function is
    > being used? I hope someone else has already done something like this and
    > will search using PPM. Source filtering comes to mind as the first choice.


    Source filtering is probably the only way as it happens early enough,
    namely at scan-time. But it's a heavy and in parts error-prone weapon.
    But then I don't entirely understand your issue. If you have functions
    in a module then you need to include this module in your programs
    anyway. Do it with 'use' and no issues will arise.

    Tassilo
    --
    use bigint;
    $n=71423350343770280161397026330337371139054411854220053437565440;
    $m=-8,;;$_=$n&(0xff)<<$m,,$_>>=$m,,print+chr,,while(($m+=8)<=200);
     
    Tassilo v. Parseval, Aug 19, 2005
    #4
  5. Re: Dynamic Typing, Defencive Programming and Prototypes (Was: Interfaces and Type Safety)

    Tassilo v. Parseval wrote:
    >> better if I could be warned audibly by emiting the bell char \a
    >> reckon that's a no-can-do in Win32 as signals aren't implemented and
    >> END blocks not run when you die.

    > Don't the pseudo-signals __WARN__ and __DIE__ work on windows, too?
    > use warningsd FATAL => 'all';
    > $SIG{ __DIE__ } = sub {
    > for (1 .. 10) {
    > print STDERR "\a"; # need auto-flushed handle here
    > select undef, undef, undef, 0.2;
    > }
    > }


    I'm not actually sure having never delt with signals before. It would seem
    your example compiles but as soon as I try doing something after this sig
    handler definition, I get a syntax error. Most likely my bad, though.

    > Or use one of the Win32 modules to emmit this annoying "oh-oh" Windows
    > system sound. :)

    I've turned all system sounds off explicitely so I'm not sure what It'll
    play if anything. Maybe the good old standard beep from the PC Speaker.

    Overloading:
    > Note that tied hashes or arrays are conceptually overloading the subscript
    > operator.

    Yes, it seems so. Still I don't mind, that's awfully convenient and the
    semantics are clear, too, especially the database examples I've seen. As to
    bad operator overloading I've never liked the bitshits doing printing and
    input in C++ as there's already a clearly defined meaning for those ops.
    Still you have to choose some existing operator to overload if any,

    Prototypes:
    > The need for pre-declarations in certain languages has to do with the
    > way the compilers are implemented.

    I guessed that, though I must confess I know next to nothing about compiler
    design. Another logical way to look at it is that it's unlikely that Perl
    would have intentional, syntactic sault for dealing with prototypes. It is
    easy to typo either of the two protos, the forward declaration or the actual
    proto before the function body, which results in a prototype mismatch. C's
    include files, forward declarations and a zillion other things have caused
    me so much grief and frustration that I'm glad higher-level languages like
    Perl or Java get well around these issues.

    >> is there a way of automatically copying the
    >> prototype from the implementation and placing it before the function

    > Source filtering is probably the only way as it happens early enough,
    > But it's a heavy and in parts error-prone weapon.

    Yes, I've noticed. Source filtering was suggested to me in an earlier post
    about making Perl operators English like or such that they read out well in
    speech. I discovered after a while that it is a mixed blessing. As soon as
    you have to work on a system that's just standard, it does help if you
    haven't tweaked things an awful lot at home.

    --
    With kind regards Veli-Pekka Tätilä ()
    Accessibility, game music, synthesizers and programming:
    http://www.student.oulu.fi/~vtatila/
     
    Veli-Pekka Tätilä, Aug 19, 2005
    #5
  6. Re: Dynamic Typing, Defencive Programming and Prototypes (Was: Interfaces and Type Safety)

    Also sprach Veli-Pekka Tätilä:

    > Tassilo v. Parseval wrote:


    >> Don't the pseudo-signals __WARN__ and __DIE__ work on windows, too?
    >> use warningsd FATAL => 'all';
    >> $SIG{ __DIE__ } = sub {
    >> for (1 .. 10) {
    >> print STDERR "\a"; # need auto-flushed handle here
    >> select undef, undef, undef, 0.2;
    >> }
    >> }

    >
    > I'm not actually sure having never delt with signals before. It would seem
    > your example compiles but as soon as I try doing something after this sig
    > handler definition, I get a syntax error. Most likely my bad, though.


    Ah, sorry, as always I've forgotten the trailing semicolon behind the
    assignment of the closure. Afterall, it's an ordinary statement and no
    named function definition:

    $SIG{ __DIE__ } = sub {
    ...
    };

    Now it'll work.

    Tassilo
    --
    use bigint;
    $n=71423350343770280161397026330337371139054411854220053437565440;
    $m=-8,;;$_=$n&(0xff)<<$m,,$_>>=$m,,print+chr,,while(($m+=8)<=200);
     
    Tassilo v. Parseval, Aug 20, 2005
    #6
  7. Re: Interfaces and Type Safety, Dynamic Typing (OOP Newbie in Perl)

    Tassilo v. Parseval wrote:
    > Also sprach Veli-Pekka Tätilä:

    <snip>
    >
    >>in the Java implementation, too. And as for friends, I was testing some
    >>badly written awt code with J-Unit (is there a P-Unit or something for
    >>Perl?), and dearly wished I could just say hey gimme full access when I'm
    >>testing. In stead I had to manually hack the code changing private parts to
    >>public in places.

    >


    <snip>

    > As for P-Unit, I am not entirely familiar with what J-Unit does. As far
    > as I know it's some sort of testing framework. Similar things exist for
    > Perl. See all the Test:: modules on the CPAN that are used for most CPAN
    > modules when you do 'make test'.


    PerlUnit

    http://perlunit.sourceforge.net/


    Mark
     
    Mark Clements, Aug 20, 2005
    #7
  8. Re: Defencive Programming and DIe Handlers (Was: Dynamic Typing etc...)

    Tassilo v. Parseval wrote:
    > Ah, sorry, as always I've forgotten the trailing semicolon behind the
    > assignment of the closure.

    Ah, has happened to me loads. The same thing with Java's anonymous inner
    classes.

    > $SIG{ __DIE__ } = sub {
    > ...
    > };

    Hey thanks a bunch, works very well. In addition to running in a very strict
    mode I managed to setup myself a nice die handler. It emits the warning beep
    and prints out the error on screen. This is standard stuf so far, though.
    Additionally it uses the system's default SAPI voice, if available, to read
    out loud the "dier message". Highly cool and saves some keyboard commands as
    a screen reader user.

    --
    With kind regards Veli-Pekka Tätilä ()
    Accessibility, game music, synthesizers and programming:
    http://www.student.oulu.fi/~vtatila/
     
    Veli-Pekka Tätilä, Aug 20, 2005
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Learner
    Replies:
    1
    Views:
    355
    Kevin Spencer
    Jan 3, 2006
  2. Oliver Wong
    Replies:
    16
    Views:
    616
    Oliver Wong
    Jun 28, 2006
  3. josh
    Replies:
    6
    Views:
    443
    Ed Kirwan
    Dec 19, 2006
  4. Replies:
    4
    Views:
    406
    Neil Cerutti
    Nov 15, 2005
  5. Replies:
    13
    Views:
    744
    Dave Rahardja
    Feb 2, 2007
Loading...

Share This Page