Implementing Interfaces and Type Safety (OOP Newbie in Perl)

  • Thread starter Veli-Pekka Tätilä
  • Start date
V

Veli-Pekka Tätilä

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>
 
T

Tassilo v. Parseval

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
 
V

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.

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.
 
T

Tassilo v. Parseval

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

defencive programming:
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:
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:
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
 
V

Veli-Pekka Tätilä

Tassilo said:
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.
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.
 
T

Tassilo v. Parseval

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

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
 
V

Veli-Pekka Tätilä

Tassilo said:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top