copy contructor

M

Moritz Karbach

Hi,

I'm writing some code in object oriented Perl, and I'm missing a default
copy constructor. Are there some default workarounds?

I heard somewhere, that there is an array or a hash containing all names of
the variables of a class / package. Can't remember how it was called. Maybe
one could use this to copy the attributes?

Cheers,

- Moritz
 
P

Paul Lalli

Moritz said:
I'm writing some code in object oriented Perl, and I'm missing a default
copy constructor. Are there some default workarounds?

I don't have my Camel on me, but ISTR the chapter on overloading talks
about overloading the = operator as a copy constructor. This copy
constructor is called by *other* overloaded operators that somehow
"know" a copy is needed.

If you really just want to write a subroutine to copy an object, I
would suggest looking into the dclone() function of the Storable
module, or the Clone module available on CPAN.
I heard somewhere, that there is an array or a hash containing all names of
the variables of a class / package. Can't remember how it was called. Maybe
one could use this to copy the attributes?

You're talking about the symbol table. The symbol table can be
accessed as a hash variable named by the package name followed by two
colons. So package Foo's symbol table is:
%{Foo::}
By inspecting the keys of this hash, you could find the name of all the
package variables and subroutines the package contains. (Note that a
simple inspection of this hash will not reveal the variables'
values.... search the perldocs for "typeglobs" for more information on
those...)

Paul Lalli
 
A

Anno Siegel

Moritz Karbach said:
Hi,

I'm writing some code in object oriented Perl, and I'm missing a default
copy constructor. Are there some default workarounds?

Huh? Standard OO doesn't know about copy constructors. They come
into play with operator overloading, but even then you don't necessarily
have to define one. You *can* use one to give overloaded mutators
like "+=" the expected semantics, but that's a subtlety.
I heard somewhere, that there is an array or a hash containing all names of
the variables of a class / package. Can't remember how it was called. Maybe
one could use this to copy the attributes?

What do attributes have to do with it?

A package My::package has a so-called stash %My::package:: associated with
it. Its keys are the names of symbols that are defined in the package,
its values are the corresponding typeglobs. So "print "$_\n" for
keys %main::;" prints all the symbols in package main. But for the
life of me I don't see what this has to do with a copy constructor.

Anno
 
A

A. Sinan Unur

T

T Beck

A. Sinan Unur said:
I'm writing some code in object oriented Perl, and I'm missing a
default copy constructor. Are there some default workarounds?


As others have pointed out, I am not sure how you came up with the
requirement to have a copy constructor.


For those of you not getting this, C++ provides you with a copy
constructor by default. The concept is, if you have an object, it's
usually a good idea to know how to copy it. It's one of the big 3.
Copy Constructor, Overloaded = operator, and a destructor. (google the
law of the big three, if you're interested, which I note you're
probably not)
In Java this isn't as much the case... you have to make something
cloneable before you can give it a clone() function, which serves as
the copy constructor (more or less..)

Now my experience with Perl in OO is pretty limited, so I can't speak
to whether or not copy constructors are good or bad (or neither) in
Perl, but if you're coming from C++, you certainly expect to see at
least a default copy constructor, if nothing else.
 
M

Moritz Karbach

I'm writing some code in object oriented Perl, and I'm missing a default
Huh? Standard OO doesn't know about copy constructors. They come
into play with operator overloading, but even then you don't necessarily
have to define one.

You're right. But IIRC at least C++ copies all attributes (or class members
or how you call it) of a class, if you say

Class1 object1;
Class1 object2;

/* modify members of object2... */

object1 = object2;

using the "standard copy constructor".


But nevertheless, my problem is simply the following: I've got a class with
about 50 attributes, and I need to get a exact clone of an object of this
class.

Therefore I've written a clone() method like

sub clone # ()
{
my $this = shift;
my $clone = new ClassName();

$clone->{att1} = $this->{att1};

# ...

@{$clone->{arr1}} = @{$this->{arr1}};

# ...

%{$clone->{hash1}} = %{$this->{hash1}};

return $clone;
}

Since this gets really huge and I'll also have to adjust this if I'm going
to add some new attributes, I was looking for an alternative a little more
sexy.

Cheers,

- Moritz
 
P

Paul Lalli

Moritz said:
You're right. But IIRC at least C++ copies all attributes (or class members
or how you call it) of a class, if you say

Class1 object1;
Class1 object2;

/* modify members of object2... */

object1 = object2;

using the "standard copy constructor".

It's been a while since I did C++, but doesn't this only do shallow
copies of any pointers within the object?

So how is this different than just assigning the object to a new
variable in Perl?

my $newobj = $oldobj;
But nevertheless, my problem is simply the following: I've got a class with
about 50 attributes, and I need to get a exact clone of an object of this
class.

Therefore I've written a clone() method like
<snip>

That's what I don't get. Other messages in this thread have already
pointed you to two modules that do this for you. Why would you want to
write one yourself? Especially one that's less extensible?

Paul Lalli
 
M

Moritz Karbach

Paul said:
Why would you want to
write one yourself?

Actually I had written it before I asked here :) Surely I will have a look
at this module.

Cheers,

- Moritz
 
T

Tad McClellan

So how is this different than just assigning the object to a new
variable in Perl?

my $newobj = $oldobj;


There is only one object there (with 2 ways to access it).

(assuming assignment has not been overloaded)

A "copy" implies that there are two separate objects (that just
happen to contain identical data).
 
A

A. Sinan Unur

Misquoted me as having said:

Learn to quote properly, and get a proper newsreader, before professing.
I never said the above. You are lying. Lying is not good.
As others have pointed out, I am not sure how you came up with the
requirement to have a copy constructor.

I know, I do not.
For those of you not getting this,

and for you,

*PLONK*
*PLONK* *PLONK*
*PLONK* *PLONK* *PLONK* *PLONK* *PLONK* *PLONK* *PLONK*

There. *Sigh*

Sinan
 
A

Anno Siegel

Abigail said:
Moritz Karbach ([email protected]) wrote on MMMMCCCXXXVI September
MCMXCIII in <URL:[] >> I'm writing some code in object oriented Perl, and I'm missing a default
[] >> copy constructor. Are there some default workarounds?
[] >
[] > Huh? Standard OO doesn't know about copy constructors. They come
[] > into play with operator overloading, but even then you don't necessarily
[] > have to define one.
[]
[] You're right. But IIRC at least C++ copies all attributes (or class members
[] or how you call it) of a class, if you say

Yeah, C++ has. But then, C++ has attributes, Perl doesn't. Perl has the
least language support I've ever seen for doing OO - it doesn't even have
attributes.

And the step from "no attributes" to "no functionality to copy attributes"
is trivial.


My advice: if you really want to do OO, use a different language.

The problem isn't so much that real OO couldn't be done in Perl, but
that what the language lacks in support must be supplied by the programmer,
and it can be supplied in various incompatible ways. This is a point
where Perl's TIMTOWTDI becomes a problem.

A lot would be gained if the role of accessors in Perl OO were better
appreciated. Any method that de-references its object is an accessor,
and an (inheriting) client class may have to override all of them. So it
needs to know which they are, and it is good to restrict them in number.

Usually that only means to define a few field accessors in the usual way,
and then *base all other methods on them*. There is much so-called Perl OO
code about that accesses the object all over the place and is almost
impossible to inherit from. More complex accessors are sometimes wanted
for efficiency or flexibility. They must be clearly documented so that
a client class knows how to override them.

A parent class that is designed (and maintained) to these principles
can be safely and relatively painlessly inherited from even across
changes in implementation.

Anno
 
A

Anno Siegel

Abigail said:
Anno Siegel ([email protected]) wrote on MMMMCCCXXXVIII
September MCMXCIII in <URL:## Abigail <[email protected]> wrote in comp.lang.perl.misc:

[Perl OO doesn't support attributes]
## > And the step from "no attributes" to "no functionality to copy attributes"
## > is trivial.
## >
## >
## > My advice: if you really want to do OO, use a different language.
##
## The problem isn't so much that real OO couldn't be done in Perl, but

Oh, I never said OO couldn't be done in Perl. OO can be done in any
language. Witness the perl source, which is (mostly) OO written in
the C preprocessor macros ;-)

Oh sure. You can do that without any support from the language. Just
like it was noted early on that you can write structured programs in
assembler and Fortran with just a little discipline.
## that what the language lacks in support must be supplied by the programmer,
## and it can be supplied in various incompatible ways. This is a point
## where Perl's TIMTOWTDI becomes a problem.

Indeed. As Larry said, Perl's OO system was an excercise in in making
something as minimal as possible.

## A lot would be gained if the role of accessors in Perl OO were better
## appreciated. Any method that de-references its object is an accessor,
## and an (inheriting) client class may have to override all of them. So it
## needs to know which they are, and it is good to restrict them in number.

Accessors don't solve the fundamental problem OO in Perl has: lack of
attributes.

But they do, or, if they don't solve the problem, they isolate it and
allow to work around it.
Getting to the attributes isn't a problem - it's the (lack
of the) attributes that are the problem:

I'm not sure what you mean here. Getting to the attributes which don't
exist anyway isn't a problem?
most approaches to do OO in
Perl, including the de facto standard (refs to hashes) break encapsulation
as soon as you want to do inheritance.

Well yes, if you do what I like to call "inheritance by usurpation": Take
the parent object as it is and implant your own fields in it. That
allows you to inherit the fields of the parent class (that is, you
inherit the accessors, and they work with your objects), but indeed it
breaks encapsulation in a major way.

This style can only be used when two or more classes are developed and
maintained together and are not expected to part ways ever. For a
public class, the style is useless.
## Usually that only means to define a few field accessors in the usual way,
## and then *base all other methods on them*. There is much so-called Perl OO
## code about that accesses the object all over the place and is almost
## impossible to inherit from. More complex accessors are sometimes wanted
## for efficiency or flexibility. They must be clearly documented so that
## a client class knows how to override them.

One can use the most beautiful accessors, and rigorously use accessors
all over the place (and nothing but accessors) - if your implementation
of objects is wrong (for instance, you're stuffing your attributes in
refs to hashes) encapsulation has to be broken to do inheritance.

I'm taking a slightly different view. Rule one: In Perl OO, there are
no such things as attributes, their role is taken by accessors to the
object. Rule two: No accessor can be inherited from a base class,
it *must* be overridden in the inheriting class. All other (object)
methods can be inherited.

Following these rules, inheritance happens without breach of encapsulation,
and it is exactly clear what must be done to support it: Override all
accessors.

Of course, inheritance by usurpation is ruled out this way. The
inheriting class doesn't even know if the parent is implemented using
a hash ref.
## A parent class that is designed (and maintained) to these principles
## can be safely and relatively painlessly inherited from even across
## changes in implementation.

Any class that doesn't solve the attribute problem is (IMNHO) worthless.
No matter how many layers of sugarcoat in the form of accessors are being
used.

In my opinion, class design around accessors does solve the attribute
problem. Whether the solution is satisfactory (generally, or for a
specific problem) is another question.

Anno
 
T

T Beck

#THIS IS THE QUOTE> Learn to quote properly, and get a proper
newsreader, before professing.
#THIS IS THE QUOTE> I never said the above. You are lying. Lying is not
good.


Do those delimeters work? Because, I can add more symbols in...
symbols make ya happy?

I'm sorry, I just kind of assumed that... you know, in the presence of
right angle brackets, most people can grasp the context that you were
quoting someone else, and then responding. I hate that I mis-quoted
your quote, but if we get into meta-quoting semantics here, it's just
gonna drive me insane.

As for my reason: Ultimately, I post ~2 things to newsgroups per week,
while I'm at work. groups.google.com works fine for me. I sincerely
didn't mean to upset you with my quoting semantics, but I was just
dropping a quick note to stick up for the OP, who seems to be used to
writing in C++, and who seems to have caused about 7 people undue
irritation by merely {suggesting} that a copy constructor exist. I'll
try not to repeat the mistake again.
 
A

A. Sinan Unur

#THIS IS THE QUOTE> Learn to quote properly, and get a proper
newsreader, before professing.
#THIS IS THE QUOTE> I never said the above. You are lying. Lying is
not good.

Do those delimeters work? Because, I can add more symbols in...
symbols make ya happy?

It is interesting what discoveries one can make by moving to a
different computer. I think I need a distributed killfile system.

I am not sure what part of "you attributed someone else's words
to me" you are unable to understand.

You did that in

<URL:http://groups-beta.google.com/group/comp.lang.perl.misc/msg/97d1c4736dc18aed>

The words you attributed to me in that message were not my words.

At least I get the pleasure of killfiling you on another computer.
if we get into meta-quoting semantics here, it's just gonna drive
me insane.

It is very simple. Don't say I said something I did not say. It
does not have anything to do with angle brackets.

*PLONK*

Sinan
 
T

T Beck

I honestly never intended for this to turn into some kind of flame
war.. Yes, I got lazy and just copied your quote with borders of
spaces around it. Yes, when I checked, the main group view of google
groups properly colorized and made everything look like your quote (as
I intended it to). Yes, your quote also included you quoting someone
else. And finally, yes, it could be misconstrued that I was trying to
use your words in the same thread and make it look like you were the
OP. But it was a simple mistake.

Now, it's not a good idea to start out by calling me a liar. You make
it sound as though I've put libel about you out here. There was an
ambiguous quoting, don't get overworked. Also, I consider it extreme
(to say the least) to killfile someone for one little mistake. But
since you {did}, all I can say is, I hope you're slightly nicer to
people IRL, because if not, I'd hate to be your coworker.

That notwithstanding, I'm dropping this topic, because you seem to have
a hate on about it regardless...
 
A

Anno Siegel

Abigail said:
Anno Siegel ([email protected]) wrote on MMMMCCCXXXIX
September MCMXCIII in <URL:
[ Snip ]

&& In my opinion, class design around accessors does solve the attribute
&& problem. Whether the solution is satisfactory (generally, or for a
&& specific problem) is another question.


Just one question: how are you storing your attributes?

Any old way. The standard hash-as-a-record, its equivalent for
arrays, whatever the base type has to offer. The derived class
doesn't know, that's why it *has* to override all accessors.
If these are few and well known, the effort is expendable. The
rest of the class follows suit. You can well have an array class
inherit in this way from a hash class, and other combinations.

I'll give an example. In the code below, a class Parent has two
fields (attributes), alpha and beta. It also has the method total
which returns the sum of alpha and beta. It is implemented as
an array of two elements.

A class Client, implemented as the usual hash, wants to keep the role
of alpha, but split the field beta into the sum of its other fields
gamma and delta. It wants to inherit the ->total method from Parent,
which should thus be the sum of alpha, gamma and delta.

My point is that the method ->total, written to form the sum of a
two-element array, now forms the sum of a three-element hash.

Anno

#!/usr/local/bin/perl
use strict; use warnings; $| = 1;

my $c = Client->new( 5, 6, 7);
print "$_ -> ", $c->$_, "\n" for qw( alpha beta gamma delta total);

##########################################################################

package Parent;

sub new {
my $class = shift;
my ( $alpha, $beta) = @_;
bless [ $alpha, $beta], $class;
}

sub alpha { $_[ 0]->[ 0] }
sub beta { $_[ 0]->[ 1] }

sub total { $_[ 0]->alpha + $_[ 0]->beta }


package Client;
BEGIN { our @ISA = 'Parent' }

sub new {
my $class = shift;
my ( $alpha, $gamma, $delta) = @_;
bless {
alpha => $alpha,
gamma => $gamma,
delta => $delta,
}, $class;
}

sub alpha { $_[ 0]->{ alpha} }
sub gamma { $_[ 0]->{ gamma} }
sub delta { $_[ 0]->{ delta} }

sub beta { $_[ 0]->gamma + $_[ 0]->delta }

__END__
 
J

Jürgen Exner

T said:
I honestly never intended for this to turn into some kind of flame
war.. Yes, I got lazy and just copied your quote with borders of

Who is "you"? Who are you talking to?
It is customary to quote appropriate context such that people have a chance
to know what you are talking about.
spaces around it. Yes, when I checked, the main group view of google
groups properly colorized and made everything look like your quote (as
I intended it to).

What does Google have to do with anything except that they added a broken UI
for posting articles to their otherwise decend archive?
Now, it's not a good idea to start out by calling me a liar. You make
it sound as though I've put libel about you out here. There was an
ambiguous quoting, don't get overworked. Also, I consider it extreme

Well, would be nice to be able to see that quoting and make my own judgement
call.
Too bad that you snipped it.

jue
 
A

Anno Siegel

Abigail said:
Anno Siegel ([email protected]) wrote on MMMMCCCXXXIX
September MCMXCIII in <URL::) > Anno Siegel ([email protected]) wrote on MMMMCCCXXXIX
:) > September MCMXCIII in <URL::) >
:) > [ Snip ]
:) >
:) > && In my opinion, class design around accessors does solve the attribute
:) > && problem. Whether the solution is satisfactory (generally, or for a
:) > && specific problem) is another question.
:) >
:) >
:) > Just one question: how are you storing your attributes?
:)
:) Any old way. The standard hash-as-a-record, its equivalent for
:) arrays, whatever the base type has to offer. The derived class
:) doesn't know, that's why it *has* to override all accessors.
:) If these are few and well known, the effort is expendable. The
:) rest of the class follows suit. You can well have an array class
:) inherit in this way from a hash class, and other combinations.
:)
:) I'll give an example. In the code below, a class Parent has two
:) fields (attributes), alpha and beta. It also has the method total
:) which returns the sum of alpha and beta. It is implemented as
:) an array of two elements.
:)
:) A class Client, implemented as the usual hash, wants to keep the role
:) of alpha, but split the field beta into the sum of its other fields
:) gamma and delta. It wants to inherit the ->total method from Parent,
:) which should thus be the sum of alpha, gamma and delta.
:)
:) My point is that the method ->total, written to form the sum of a
:) two-element array, now forms the sum of a three-element hash.
:)
:) Anno
:)
:) #!/usr/local/bin/perl
:) use strict; use warnings; $| = 1;
:)
:) my $c = Client->new( 5, 6, 7);
:) print "$_ -> ", $c->$_, "\n" for qw( alpha beta gamma delta total);
:)
:) ##########################################################################
:)
:) package Parent;
:)
:) sub new {
:) my $class = shift;
:) my ( $alpha, $beta) = @_;
:) bless [ $alpha, $beta], $class;
:) }
:)
:) sub alpha { $_[ 0]->[ 0] }
:) sub beta { $_[ 0]->[ 1] }
:)
:) sub total { $_[ 0]->alpha + $_[ 0]->beta }
:)
:)
:) package Client;
:) BEGIN { our @ISA = 'Parent' }
:)
:) sub new {
:) my $class = shift;
:) my ( $alpha, $gamma, $delta) = @_;
:) bless {
:) alpha => $alpha,
:) gamma => $gamma,
:) delta => $delta,
:) }, $class;
:) }
:)
:) sub alpha { $_[ 0]->{ alpha} }
:) sub gamma { $_[ 0]->{ gamma} }
:) sub delta { $_[ 0]->{ delta} }
:)
:) sub beta { $_[ 0]->gamma + $_[ 0]->delta }
:)
:) __END__


Well, that "works", but that kind of defeats the purpose of using OO:
reusing code.

Well, you *can't* reuse accessors and be implementation-independent.
Rule of the game, no two ways about it.
You will have to redefined *every* method of a parent class.

Only those methods that de-reference their object. This example
class has only one non-accessor ->total, but that's only an example.
In a real class the balance will be far more in favor of non-accessors,
especially if the class is written with this in mind.
Take for instance the above example - since you aren't going to break
encapsulation, you don't know how the class is implemented. It might as
well be:


package Parent;

sub new {
my $class = shift;
my ( $alpha, $beta) = @_;
bless [ $alpha, $beta, $alpha + $beta ], $class;
}

sub alpha { $_[ 0]->[ 0] }
sub beta { $_[ 0]->[ 1] }

sub total { $_[ 0]->[ 2] }


It has the same interface, but if you now create your Client class
as presented, calling the method 'total' results in "Not an ARRAY reference".

Same interface, but now you have made ->total is an accessor and yes,
that means it must be overridden.
You have to redefine any method that touches an attribute directly - and
you either have to peek inside (breaking encapsulation) to know which
methods touch an attribute - or redefine every method.

That's why I'm preaching that accessors must be documented. An inheriting
class must know what they are and how to override them.
But if you redefine every method, what's the point of inheritance?

That's why carelessly written classes that access their objects all over
the place are useless for inheritance. A good class defines a handful
of accessors and then never touches the object again. Then most of the
useful stuff *can* be inherited.

If the inheriting class has an object of the base class a component,
(so the is-a relation is based on a has-a relation), even accessors
can be made inheritable with a little trick the base class must provide.
I'll post a rewrite of my example a little later.

Anno
 
A

Anno Siegel

[big snip]
That's why carelessly written classes that access their objects all over
the place are useless for inheritance. A good class defines a handful
of accessors and then never touches the object again. Then most of the
useful stuff *can* be inherited.

If the inheriting class has an object of the base class a component,
^^^^^^^^^^^^^^^^^^^^^^

That should have been "...base class *as* a component", sorry.
(so the is-a relation is based on a has-a relation), even accessors
can be made inheritable with a little trick the base class must provide.
I'll post a rewrite of my example a little later.

Okay, here goes.

The code for the base class is mostly unchanged. The only difference is
that it inserts a do-nothing method (one that just returns its object) into
all of its accessors (not in other methods). So if the accessor was

sub alpha { $_[ 0]->[ 0] }

it becomes

sub alpha { $_[ 0]->parent->[ 0] }
# ...
sub parent { shift }

Obviously, this doesn't change the behavior of the class, except for
wasting some time (but we're doing OO here, Efficiency is down the hall).
So clients who don't know about the change continue to function.

The no-op is called like the class (de-emphasized by lower-casing). It
could, of course, be called anything, but that is a good choice from the
clients point of view if the client chooses to use the facility.

It does that by defining a field that holds an object of class Parent
and calling the accessor to that field "parent", so it overrides that
method in the base class.

sub new {
# ...
bless {
parent => Parent->new( ...),
# ...
}, $class;
}

sub parent { $_[ 0]->{ parent} }

The effect is that the base class, when it comes to accessing an object,
interpolates the 'parent' method and sees an object of its own class which
it can handle.

This alone allows the client to inherit from Parent, that is, it can
put "Parent" on @ISA and all Parent methods will work using the parent
component. Thus it must override only one method. It can go on to
override specific other methods to modify the behavior.

So here is my original example re-written this way. The class Client_orig
is how it must be done (well, one way) without the ->parent method. It
still works with the modified Parent, but the modified Client is more
orderly.

Anno

#!/usr/local/bin/perl
use strict; use warnings; $| = 1;
use Vi::QuickFix;

my $c = Client->new( 5, 6, 7);
print "$_ -> ", $c->$_, "\n" for qw( alpha beta gamma delta total);

##########################################################################

package Parent;

sub new {
my $class = shift;
my ( $alpha, $beta) = @_;
bless [ $alpha, $beta], $class;
}

sub parent { shift }

sub alpha { $_[ 0]->parent->[ 0] }
sub beta { $_[ 0]->parent->[ 1] }

sub total { $_[ 0]->alpha + $_[ 0]->beta }

##########################################################################

package Client;
BEGIN { our @ISA = 'Parent' }

sub new {
my $class = shift;
my ( $alpha, $gamma, $delta) @_;
bless {
parent => Parent->new( $alpha, undef),
gamma => $gamma,
delta => $delta,
}, $class,
}

sub parent { $_[ 0]->{ parent} }
sub gamma { $_[ 0]->{ gamma} }
sub delta { $_[ 0]->{ delta} }

sub beta { $_[ 0]->gamma + $_[ 0]->delta }

##########################################################################

package Client_orig;
BEGIN { our @ISA = 'Parent' }

sub new {
my $class = shift;
my ( $alpha, $gamma, $delta) = @_;
bless {
alpha => $alpha,
gamma => $gamma,
delta => $delta,
}, $class;
}

sub alpha { $_[ 0]->{ alpha} }
sub gamma { $_[ 0]->{ gamma} }
sub delta { $_[ 0]->{ delta} }

sub beta { $_[ 0]->gamma + $_[ 0]->delta }

__END__
 
A

A. Sinan Unur

(e-mail address removed)-berlin.de (Anno Siegel) wrote in
The code for the base class is mostly unchanged. The only difference
is that it inserts a do-nothing method (one that just returns its
object) into all of its accessors (not in other methods). So if the
accessor was

sub alpha { $_[ 0]->[ 0] }

it becomes

sub alpha { $_[ 0]->parent->[ 0] }
# ...
sub parent { shift }

[ rest of the discussion and code snipped ]

Anno:

I wanted to thank you very much for this series of posts, especially
this last one. I found it very informative.

Sinan
 

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
474,172
Messages
2,570,934
Members
47,478
Latest member
ReginaldVi

Latest Threads

Top