6

first post from a newbie-user. Every question I google seems to bring me here and I always get a great answer to what I'm looking for; so naturally this was my first stop when I began pondering the usage of blessing in Perl.

I've just gotten into Perl's OOP and just today read the post asking what bless does. I now understand that it references a scalar/hash/array to an object, 'attaching' it, if you will.

In most of the examples of classes I see in Perl, they don't seem to have properties like I'm used to seeing in other languages...

{ package Person;
    my $property = "This is what I'm talking about :)";

    sub new { ... }
    ...
}

So, I created a stupid class with a property to see what would happen. I gave the property the value 'NIL' right off the bat and then 'Not Nil!' in the constructor. Using a method LIST, I was able to print the property, and as I expected, it printed 'Not Nil!'

My question is, if properties work the same as I expected them to work (declared in the body) then why use bless at all? What is the added benefit of having that reference when you could simply create a scalar/hash/array as a property, or create whatever references you want as a property?

I hope I explained what I'm trying to ask well enough, very green with Perl :)

NiRC
  • 61
  • 2
  • I wonder when they'll get around to implementing "smite"... – Jim Lewis Aug 11 '10 at 03:25
  • Wow, I didn't really realize my question was that stupid... Sorry?.. I'll be taking your advice now Hamish. – NiRC Aug 11 '10 at 03:31
  • 3
    I'm not sure what @Hamish Grubijan is saying, but your question isn't stupid. My guess is that he's saying that Perl is not a well-regarded language on average on this site, but Perl questions are welcome :) – Jacob Aug 11 '10 at 04:02
  • 2
    @NiRC - settle down... Hamish was making an somewhat failed joke, which was 98% on Perl and 2% on you... as in "Perl is so bad/scary, you should quit trying to deal with it before you get sucked into it any deeper". – DVK Aug 11 '10 at 04:08
  • Ah, I see said the _very_ blind man, I was starting to wonder why I couldn't see what was apparently right in front of my face! :D Feeling quite foolish now – NiRC Aug 11 '10 at 04:12
  • 4
    @Jim Lewis: Seven years ago. http://search.cpan.org/~ibb/Acme-Damn-0.02/Damn.pm Smite isn't one of the aliases, maybe you should make a request. – Matthew S Aug 11 '10 at 04:39
  • @NiRC - you're voluintarily learning Perl... not sure about foolish but you are quite certainly certifyably insane, in my professional opinion (as a fellow insane person :) ) – DVK Aug 11 '10 at 10:41
  • lol @DVK I'm loving it too, I think it's much more readable than Ruby or Python. Ruby I've never touched to be honest though, Python I've played around a little with – NiRC Aug 11 '10 at 14:51
  • Along the lines of DVK's answer, check out http://stackoverflow.com/questions/1761109/practical-uses-of-oop/1761160#1761160 Also, if you want to learn a lot about how to use and abuse Perl OOP, check out Damian Conway's classic book `Object Oriented Perl`. However, for practical Perl OOP, you are almost always better off to use Moose these days. – daotoad Aug 12 '10 at 06:45

4 Answers4

11

Well, that is not how you create classes in Perl.

Your $property variable is defined in package scope. Therefore, there will only one copy of it per class rather than each object having its own copy.

One might implement such a class using hash based objects the long and hard way as below:

#!/usr/bin/perl

package Person;

use strict; use warnings;

sub new {
    my $class = shift;
    my $self = {};
    bless $self => $class;

    my ($arg) = @_;
    for my $property ( qw( message ) ) {
        if ( exists $arg->{$property} ) {
            $self->$property($arg->{$property});
        }
    }
    return $self;
}

sub message {
    my $self = shift;
    return $self->{message} unless @_;
    my ($msg) = @_;
    $self->{message} = $msg;
}

package main;

my $person = Person->new({
    message => "This is what I'm talking about :)"
});

print $person->message, "\n";

Now, this gets tedious fast. So, there are modules that help you deal with this as well as helping you define your classes in way that is safe for inheritance.

Class::Accessor is one such utility module.

For programs where startup time is not an issue, you should consider Moose. With Moose, you can write the above as:

#!/usr/bin/perl

package Person;

use Moose;

has 'message' => (is => 'rw', isa => 'Str');

__PACKAGE__->meta->make_immutable;
no Moose;

package main;

my $person = Person->new({
    message => "This is what I'm talking about :)"
});

print $person->message, "\n";

You should read perldoc perltoot and Moose::Manual::Unsweetened for the standard way of doing things.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
  • 1
    Thanks a TON for this post, very useful links. I'd been using perldoc a bit, but a lot of the documentation is very.. intimidating to say the least :) – NiRC Aug 11 '10 at 04:11
  • @NiRC - I'd strongly suggest hitting up a couple of books (there's pribably a StackOverflow question on Perl books already so I won't bother recommending, other than the Usual Suspects - O'Reilly Perl series). Perl documentation is not necessarily a great learning material, I'm afraid (as opposed to being a great reference material once you're past initial learning curve) – DVK Aug 11 '10 at 04:21
  • @Sinan = +1 for Moose. And a probational -1 for writing separate getter and setter as opposed to a unified "if no arguments, i'm a getter" method, ala results from Class::Accessor::Fast :) – DVK Aug 11 '10 at 04:24
  • @DVK Fine, have it your way. But, note `Class::Accessor->follow_best_practice` ;-) – Sinan Ünür Aug 11 '10 at 04:33
  • You know I just read this whole thing and I'm not sure you answered the question... "if it already works as expected, why use bless?" – xenoterracide Aug 11 '10 at 04:57
  • 1
    The second paragraph shows that it does *not* work as expected. – Thomas Kappler Aug 11 '10 at 07:28
  • @Xeno - Ya, I can see where I was confused, I thought a package, declared in that sense, was virtually a 'class' definition as opposed to a namespace. Where I thought I was using a class property I was just using a public variable. – NiRC Aug 11 '10 at 14:53
  • If you just want to hold data, you *don't* need to use bless. Indeed it's quite normal to pass around data structures that are simply nested hashes/arrays. Bless is used when one wants to associate that data with code that can manipulate that data -- so the data is blessed into a package which has methods that can operate on that specific object instance. – Ether Aug 11 '10 at 16:59
  • 1
    @Ether: Yes, but the use of the term "property" strongly suggests that the OP wants to associate the data with code that can manipulate those data. – Sinan Ünür Aug 11 '10 at 20:04
8

What you did with $property in this case is declared a variable in the "Person" package's scope. You change that inside (or outside using $Person::property) of the package, and any object that refers to it will see the updated variable, so it acts a lot like a "static attribute (Java)" without any real "private" scope. By convention, hidden things in Perl ("private" or "protected") are prefixed with an underscore, but of course this isn't enforced.

You don't actually make a new class, as you pointed out, with the "package" keyword; you can use "package" without OOP at all. That simply creates a separate "namespace".

The advantage of "blessing" a variable, almost always a hash reference from what I've seen, is that you can have methods, just like any other OOP language. Just remember to bless whatever you return in the new {} subroutine ("new" isn't actually a reserved word; just a convention). When you call a method on the "object" (a blessed data structure like a hashref), the first argument of the method is the data structure itself. So, if you have a hashref called $myobject, which is blessed to AwesomeClass, and you define a method in AwesomeClass called doSomethingAwesome, which needs to accept one variable, you would have to "shift" @_ (which is the argument list of the subroutine, or use $_[0]) to access the $myobject hashref. Python does something similar, and all languages pass the object reference to the method somehow. ("this" keyword in many, see also "thiscall" calling convention)

NB: I've seen lots Perl bashing in my time, which has only been a few years as a programmer. Perl is an awesome language that was made by a very smart linguist (Larry Wall) and has a fanatical following -- more fanatical at one time than Ruby, perhaps, but not as much as David Koresh). Perl does things very differently than lots of languages but if you look at code golf entries on this site and others, you can clearly see that much can be accomplished with very little Perl (no guarantees about code legibility, especially for newcomers!)

Hut8
  • 6,080
  • 4
  • 42
  • 59
  • Thanks a lot! I see what you're saying now. Perl is indeed very different from the C# that I'm used to :) – NiRC Aug 11 '10 at 04:10
  • 3
    If David Koresh was anything like Perl, there would be More Than One Way To Exit The Damned Compound! And More Than One Fire Suppressant Module. – DVK Aug 11 '10 at 04:27
5

The value of bless'ing an object is getting to use the methods from a particular package.

package MyClass;
sub answer { my ($self)=@_; return $self->{foo} * 42; }

package main;
my $object1 = { foo => 1, bar => "\t" };
my $object2 = bless { foo => 2, bar => "\t" }, "MyClass";

$ref1 = ref $object1;        #  'HASH'
$ref2 = ref $object2;        #  'MyClass'

$answer1 = $object1->answer;     # run time error
$answer2 = $object2->answer;     # calls MyClass::answer, returns 2 * 42 = 84
mob
  • 117,087
  • 18
  • 149
  • 283
4

Ugh... Sinan's answer is entirely too learned for my taste, at least past 12am :)

So I'll give a shorter and somewhat less Perly one, just for variety's sake.

Your question is not really about Perl as far as I can tell, and can be just as easily ased in another form: "Why bother using C++ and OOP in it when C already has structs?"

In other words, you seem to be asking what the point of using OOP paradigm is.

The answer is of course that it helps solving certain software engineering problems easier than pure procedural programming. Emphasis on certain - OOP is not a panacea for every problem, any more than ANY technique/approach/paradigm is.

Using OOP (in a form of packages as classes and blessed hashes as objects in Perl) allows you to enjoy the benefits of inheritance, polymorphism and other OOPyish mumbo-jumbo which you are probably already fairly familiar with from you non-Perl OOP experience.

Can you do 100% of what you'd have done with a blessed object with a pure data structure? Absolutely. Would 100% of it be just as easy/short/readable/maintainable code as you can achieve using objects? Most likely not, though it depends on how well your OOP code actually leverages the benefits that OOP provides (BTW, I have encountered supposedly OOP code (Perl and not) which wasn't really taking any advantage of OOP paradigm and could have been made easier to read and understand had it been stripped of its OOP chrome).

DVK
  • 126,886
  • 32
  • 213
  • 327
  • 1
    You are still too learned! :) IME, inheritance and polymorphism are nice touches, but the real payoff with OOP is that it provides a clean and easy way to associate behaviors with data. Some of my OOP projects use polymorphism and inheritance. But all of them take advantage of clear association of data and actions. Instead of looking at a complex multilayer structure and 27 associated functions, I can have Foo and Bar objects that are contained by nice Baz object--dividing the 27 methods between the classes as appropriate. – daotoad Aug 12 '10 at 06:53