I recently started using the module MooseX::Declare. I love it for its syntax. It's elegant and neat. Has anyone come across cases where you would want to write many functions (some of them big) inside a class and the class definition running into pages? Is there any workaround to make the class definition to just have the functions declared and the real function definition outside the class?
What I am look for is something like this -
class BankAccount {
has 'balance' => ( isa => 'Num', is => 'rw', default => 0 );
# Functions Declaration.
method deposit(Num $amount);
method withdraw(Num $amount);
}
# Function Definition.
method BankAccount::deposit (Num $amount) {
$self->balance( $self->balance + $amount );
}
method BankAccount::withdraw (Num $amount) {
my $current_balance = $self->balance();
( $current_balance >= $amount )
|| confess "Account overdrawn";
$self->balance( $current_balance - $amount );
}
I can see that there is a way to make the class mutable. Does anyone know how to do it?
Easy (but needs adding to the doc).
class BankAccount is mutable {
}
As an aside, why are you defining your methods outside the class?
You can just go
class BankAccount is mutable {
method foo (Int $bar) {
# do stuff
}
}
I want my class definition to be short, and to give an abstract idea of what the class is for. I like the way its been done in C++ where you have an option to define functions inline or outside the class using the scope resolution operator. This makes the class definition short and neat. This is what I am looking for.
Thanks for your time.
Related
All OOP languages support having a variable refer to an object. But some languages also support having a variable refer to a class (class-reference type). Say I have a method that will accept either an object or a class as its parameter. What would I call the parameter? In other words, is there a term that both encapsulates "object" and "class"?
To further clarify, here's some (otherwise useless) PHP code that illustrates what I mean by class reference vs object reference:
<?php
class Foo {
public function shout(string $message) {
echo strtoupper("$message\n");
}
}
class Bar {
public function shout(string $message) {
echo "!!! $message !!!\n";
}
}
/**
* #param mixed $classOrObject
*/
function shoutOut($classOrObject) {
if (is_object($classOrObject)) {
$classOrObject->shout('I got an object');
} elseif (is_string($classOrObject)) {
$object = new $classOrObject();
$object->shout('I got a class');
}
}
shoutOut(new Foo());
shoutOut(Bar::class);
A rephrase of the question can hence be
What is a better name for the $classOrObject parameter?
As a third attempt at homing in on what I'm really after here, imagine you're writing an introduction to OOP. You could say something like
The main ingredients of the OOP paradigm are the class and object.
So if we were to substitute "main ingredients" with a more theoretically accurate term, my question is what would that term be? If classes were apples and objects were pears, we'd call them both "fruit". But classes and objects are not fruit, so what do we call them?
An object is instance of class.
A class is like mold and the object is an element created with this mold.
I want to create specific Object according to the type argument.
Pseudo code looks like this.
sub new {
my $type = shift;
if($type eq "S1") {$interface = X->new(); }
if($type eq "S2") {$interface = Y->new(); }
etc...
return $interface;
}
Options might be:
Substitute "package" name with $type argument. Requires package name coordination with $type.
Use Hash{S1 => X} in the Master constructor to select Value according to $type passed. Requires Hash maintenance when adding new
Object types.
I don't like any of above. Looking trully polimorphic way to accomplish that.
Thank You,
k
Your best option would likely be to use a factory pattern. A factory method takes the parameters for creating an instance of your class, then decides which object to instantiate and return from that. This can also make dependency injection easier for testing.
You'd probably be looking at something like this (in Java-esque code), with an employee object:
public class EmployeeFactory
{
public static create(String type)
{
switch (type) {
case type1:
return new EmployeeTypeOne();
case type2:
return new EmployeeTypeTwo();
default:
throw new Exception("Unrecognized type");
}
}
}
Your employees would inherit from a common interface or abstract class. You can use the factory to handle constructor parameters as well if you prefer, just try to keep things fairly reasonable (don't pass a million parameters - the factory should internally handle complex objects)
See http://refactoring.com/catalog/replaceConstructorWithFactoryMethod.html for more information.
You might like Module::PluginFinder for that. Create all your specific types in a specific namespace and give them each some identifying (constant? sub?) that the main dispatcher will then use to identify which class handles a given type.
I am trying to understand how lexical_has attributes work in Moops. This feature comes from Lexical::Accessor and, as I understand it, the lexical_has function is able to generate a CODE reference to any attribute a class might "lexically have" by using a scalar reference (which is kept in accessor =>). The CODE reference can then be used to access the class attribute in a way that "enforces" scope (because they are "inside out"??). But this is just my surmise and wild guesses so I would appreciate a better explanation. I also want to know why this approach doesn't seem to work in the following example:
Working from the example that is part of the Moops introduction I'm creating a class Car:
use Moops;
class Car {
lexical_has max_speed => (
is => 'rw',
isa => Int,
default => 90,
accessor => \(my $max_speed),
lazy => 1,
);
has fuel => (
is => 'rw',
isa => Int,
);
has speed => (
is => 'rw',
isa => Int,
trigger => method ($new, $old?) {
confess "Cannot travel at a speed of $new; too fast"
if $new > $self->$max_speed;
},
);
method get_top_speed() {
return $self->$max_speed;
}
}
Then I instantiate the object and try to use its methods to access its attributes:
my $solarcharged = Car->new ;
# This correctly won't compile due to $max_speed scoping:
# say $solarcharged->$max_speed;
# This shows expected error "too fast"
$solarcharged->speed(140);
# This prints nothing - wrong behavior?
say $solarcharged->get_top_speed();
The last line which uses the custom accessor baffles me: nothing happens. Am I missing an attribute or setting for the class (marking it eager or lazy => 0 doesn't work)? Do I need a BUILD function? Is there an initialization step I'm missing?
N.B. If I add a setter method to the class that looks like this:
method set_top_speed (Int $num) {
$self->$max_speed($num);
}
and then call it in my final series of statements:
# shows expected error "too fast"
$solarcharged->speed(140);
$solarcharged->set_top_speed(100);
# prints 100
say $solarcharged->get_top_speed();
the get_top_speed() method starts to return properly. Is this expected? If so, how does the default from the class settings work?
I've reported this as a bug here: https://rt.cpan.org/Public/Bug/Display.html?id=101024.
Since One can easily work around this by using "perl convention" (i.e. not using lexical_has and prefixing private attributes with "_") and this question arose from a bug, I don't expect a fix or a patch as an answer. For the bounty - I would appreciate an explanation of how Lexical::Accessor is supposed to work; how it "enforces" private internal scope on accessors; and maybe some CS theory on why that is a good thing.
According to the ticket filed by the OP, this bug was fixed in Lexical-Accessor 0.009.
class #A
A_Function_Alias: => #my_function
my_function: =>
usage_of_alias: =>
#A_Function_Alias.call()
What i want, is usage_of_alias to be
usage_of_alias: =>
#A_Function_Alias
And have it behave the same. i.e. I want a more functional style syntax here. I've tried multiple combinations with no success. The fact that i have to evaluate my function to get the goodies inside bothers me.
One application would be instead of this:
event: => new Event(#my_function)
which is accessed as event.call().hi()
i could have some other declaration that would allow me to access event as event.hi()
Something that behaves more like a field instead of a property.
I'm thinking you want this:
class #A
my_function: => alert 'my function!'
A_Function_Alias: #::my_function
usage_of_alias: =>
#A_Function_Alias()
# some other code...
See what this compiles to here.
When evaluating a class # is the class constructor object, the class object itself. And the :: operator lets you drill into the prototype. So #::foo in a class body compiles to MyClass.prototype.foo.
So what this is doing is first making a normal instance method named my_function, defined on A.prototype.my_function. Then we make a new instance method named A_Function_Alias and directly assign the function from class objects prototype that we just created. Now my_function and A_Function_Alias both point to the exact same function object.
But as a more sane alternative, might I suggest a pattern that defines a private inner function that the class can use, and then assigning it more directly, without crazy the prototype accessing?
class #A
# Only code inside this class has access to this local function
innerFunc = -> alert 'my function!'
# Assign the inner funciton to any instance methods we want.
my_function: innerFunc
A_Function_Alias: innerFunc
usage_of_alias: =>
#A_Function_Alias()
# or
#my_function()
# or
innerFunc()
# they all do the same thing
I am defining an API using roles and also defining the implementation using roles. I combine multiple implementation roles into a class just before creating objects. I am running into an issue where accessor methods are not being recognized while normal methods are. Please see code below and errors received while running it. I wonder if this is an intended behavior or a bug?
Code:
use MooseX::Declare;
role api { requires qw(mymethod myattribute); }
role impl with api {
has myattribute => (is => 'ro', default => 'zz');
method mymethod { ...; }
}
class cl with impl {}
my $obj = cl->new;
Error:
'impl' requires the method 'myattribute' to be implemented by 'cl' at D:/lab/sbp
/perl/site/lib/Moose/Meta/Role/Application/ToClass.pm line 127
So the issue here (and I think it's being masked by MooseX::Declare) is a known issue where Role composition may happen before the methods are generated by the attribute. If you change your code to move the role composition to after the attribute declaration:
role impl {
has myattribute => (is => 'ro', default => 'zz');
with qw(impl);
method mymethod { ...; }
}
and the error goes away. I thought MooseX::Declare protected you against this by moving role composition to the end of the role/class declaration but it appears that isn't the case in this instance. Perhaps someone who uses MooseX::Declare more can illuminate better what's going on there.