Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery

using constants in Derived class

by rajachan (Initiate)
on Nov 17, 2010 at 10:21 UTC ( #871974=perlquestion: print w/replies, xml ) Need Help??
rajachan has asked for the wisdom of the Perl Monks concerning the following question:

Greeting Monks. This is my first post in this wonderful forum

Help me code this scenario better.I have a baseclass named "automobile", and two derived classes named "car" and "truck". Also I have an new class named "ParkingLot", which should know what the car it is operating on, to customize the lot-size and other attributes.

Now back to the problem. The current codebase that I work on is matured and I wouldn't be able to make drastic changes. It's complete written in Perl OOPS. The "ParkingLot" constructor will always be passed with the automobile object (instantiated much before this) as an argument. The class(Parking Lot) uses this argument, does a ref on object pointer to find whether the class is "car/truck" and does some very specific operations based on vehicle type. To avoid this, I tried to make interfaces more generic and try to abstract the code inside refs to more meaningful public attribute or a private function, which can be overriden by derived class (Ex: parkingLotForTrucks and parkingLotForCars). IMHO, this would make the code more maintainable.

Where I cannot modularize/carve out functions out of code due to lack of context, for example code like below are found in lot of places (mostly the RHS of assignment is a constant number). I want to know, if I could use constants and override them in derived class, instead of defining single line functions that are not reusable?

For example, the below snippet could be changed as
if (ref $automobile eq "car") { set x = y; } else (ref $automobile eq "truck") { set x = z; } #changed to use constant Y => "STRING1"; # In Base class use constant Y => "STRING2"; # In Derived Class #In Baseclass I'll have, set x = Y;
I have read constant in baseclass could be overridden in derived class. But somehow I feel this will make code less readable, than using if-else. But it's less scalable than the Const method. I would like to know how Monks would go about this problem and make the code elegant and maintainable?

Replies are listed 'Best First'.
Re: using constants in Derived class
by moritz (Cardinal) on Nov 17, 2010 at 10:36 UTC
    I'd like to bring some curious implementation details to your attention:
    1. use constant works by automatically generating nullary subroutine that returns a constant. The optimizer then optimizes away the call, and replaces it by the constant itself.
    2. All subroutines can be used as method
    3. In method calls, the arity check from the prototype that  use contant ... installed isn't performed

    Combining these curious features, you'll notice that

    • If there was use constant a => 1 in a class, you can actually access that value with $obj->a
    • If a child class has another use constant a => 2;, the $obj->a syntax returns the value from the derived class

    So if you access the constant as methods, everything should work according to your wishes. What a coincidence :-)

    That way it's much more extensible than using a big if-elsif-else construct, and I consider that a good thing. It's a typical OO style, and if your application is already OO, it's good to conform to that stlye.

Re: using constants in Derived class
by JavaFan (Canon) on Nov 17, 2010 at 12:30 UTC
    No, it's not going to work that way. And I'm not sure you want to. But what you can do is:
    package Automobile; sub CarType {die "Ought to be overridden!"} __END__ package Car; our @ISA = qw[Automobile]; sub CarType {"STRING1"} __END__ package Truck; our @ISA = qw[Automobile]; sub CarType {"STRING2"} __END__ package ParkingLot; $x = $automobile->CarType;
    But do you really want to? I don't know your code, but it smells wrong. Perhaps you need to know the type because it matters how quickly the parking lot is full - it's the size that's important. Better is to have the ParkingLot be agnostic about what class (or type) of automobile it's dealing, and just ask the automobile for the number of slots in needs:
    package Automobile; sub covers_slots {die "Ought to be overridden!"} __END__ package Car; our @ISA = qw[Automobile]; sub covers_slots {1;} __END__ package Truck; our @ISA = qw[Automobile]; sub covers_slots {3;} __END__ package ParkingLot; $slots = $automobile->covers_slots;
    Then now if you introduce the classes "Limo", "Schoolbus" and "TinyCar", you don't have to change your ParkingLot module. And it also allows the Truck module return different numbers of covered_slots depending on the size of the truck (big trucks need more slots than small ones).

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://871974]
Approved by Corion
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (5)
As of 2017-05-25 03:12 GMT
Find Nodes?
    Voting Booth?