[ANN] Article: Seeing Metaclasses Clearly

  • Thread starter why the lucky stiff
  • Start date
L

Lyndon Samson

Problem with that is a concept that has been foward for classes that
are not visible outside a given scope. eg.

class X
private class Y
# ...
end
# ...
end

Not that Ruby has them (yet ;-) but that would most certainly be
called a "private class".

I had been holding on to the term "special class", but I suppose that
makes it sound like it has "special" needs :) Perhaps we should try a
differnt tact, like "root class" or "direct class".

ILC - Instance Local Class? A variation of Thread Local Storage.
 
M

Mark Hubbart

Strangely, I didn't get Trans' message. I'll reply in the quotes. :/


I know Java has private classes (or is it just inner classes?), but
I've never heard anyone ask for them in ruby before. Private classes
in that sense really don't seem very rubyish to me. If we'll never
have private classes in that sense, then it leaves the term open. So
that part of it would depend on the chances of Ruby ever having
limited scope classes.

"direct class" isn't bad. I would expect "root class" to be Object, though.
ILC - Instance Local Class? A variation of Thread Local Storage.

This one seems a little verbose to me. maybe just instance class?

cheers,
Mark
 
D

David A. Black

Hi --

"Own class" is the best I've heard 'till now in terms of correctness,
it's just a bit "pale". I mean, when you say "I go there by my own
car", then the "own" doesn't refer to a special type of car, it just
refers to some relation of the car with other things. It refers to a
non-intrinsic thing. But if you say
"I go there by my batcar", that makes a difference. Such a thing is
what we need for ruby.

I don't know... it may be time for a little paleness in the
terminology. All the snazzy, exciting terminology seems to cause
problems :)
What about "eigenclass", like in eigenvalue?

But eigen is just German for own. I'd rather just keep it in English.


David
 
D

David A. Black

Hi --


Naja, weiss ich schon :) I was oversimplifying. But it still feels,
I don't know, _fremd_ with respect to the texture of Ruby.
try some latin/roman word ;p

I was actually thinking about "idioclass", but decided the debate that
would ensue was too predictable to bother actually instigating :)


David
 
T

Trans

I was thinking that maybe we should look at how we get at the class
now:

(class << self ; self ; end)

that would indicate a name like "selfish_class" :)

And really the class is quite egotistical. What right does it have to
butt in so _easily_? Isn't that exactly why Matz is reluctant to settle
on a final name? On the other hand "selfish" is a little "ishy" too --I
mean, is it or isn't it? So perhaps "egotisitical_class" would do. A
little long. We could shorten to just "egoclass". Ah, yes. Now that's
fun. Now I can speculate on what is "superegoclass" :) Freud would be
proud.

Okay, cheese humor aside, "idioclass" is actually a very good term. It
is quite percise, even better than "special_class" I think.

Main Entry: idio-
Function: combining form
Etymology: Greek, from idios -- more at IDIOT
: one's own : personal : separate : distinct <idioblast>

And it has a nice technical ring too it. Which is really what all the
other suggestions lacked. Good call David.

+1

T.
 
M

Mathieu Bouchard

---1077017559-1369306703-1114308715=:17107
Content-Type: MULTIPART/MIXED; BOUNDARY="-1077017559-1369306703-1114308715=:17107"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---1077017559-1369306703-1114308715=:17107
Content-Type: TEXT/PLAIN; CHARSET=ISO-8859-1; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE
Content-ID: <[email protected]>


It also makes the name "Singleton" class a little odd. I thought it was
because a singleton class could only have a single instance. Now I find = out
it can't even have that. Perhaps they should be Zeroton classes :)

The instance-of relationship is not about creatability of new objects: it=
=20
is about which object represents the behaviour of which other object,=20
period. In the case of singleton classes, the instance is created *before*=
=20
the class is, and it doesn't follow that this peculiar creation order=20
makes that relationship a lesser-instance-of or a non-instance-of.

Where the "singleton" name really breaks is with indirect instance-of=20
relationships: for example, (Object) has many indirect instance-of=20
relationships, with *all* Ruby classes in the system, and you can=20
instantiate the (Object) class as many times as you want to, and you=20
always do whenever you are subclassing any class whatsoever, because every=
=20
instance of Class is also an instance of (Object).

(note: the general instance-of such as Module#=3D=3D=3D is transitive in th=
e=20
sense that it also includes instance-of-subclass-of and so on: every=20
object is an instance-of Object.)
The formal definition does not require metaclasses (or classes) to create
instances ... only that they /have/ instances (which is you so clearly
demonstrated singleton classes have no instances).

I have trouble following that... we seem to both agree and disagree on=20
the same thing at once...!

Maybe it's because of confusing the Object#class method with which is the=
=20
direct-instance-of relationship of an object. The latter cannot be=20
observed in Ruby: if an object x has no S-class, then it's=20
directly-instance-of the result of x.class, and if an object has a=20
S-class, it's directly-instance-of the result of (class<<x;self;end) and=20
not of x.class, but there's no way to figure out whether an object has an=
=20
S-class other than to cause that S-class to spring into existence (!).

Does this all make sense to you?

,-o---------o---------o---------o-. ,----. |
| The Diagram is the Program (TM) | | ,-o----------------------------o-.
`-o-----------------------------o-' | | Mathieu Bouchard (Montr=E9al QC)=
|
| |---' | http://artengine.ca/matju |
| | `-o------------------------------'
---1077017559-1369306703-1114308715=:17107--
---1077017559-1369306703-1114308715=:17107--
 
M

Mathieu Bouchard

---1077017559-1916148283-1114310290=:17345
Content-Type: MULTIPART/MIXED; BOUNDARY="-1077017559-1916148283-1114310290=:17345"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---1077017559-1916148283-1114310290=:17345
Content-Type: TEXT/PLAIN; CHARSET=ISO-8859-1; FORMAT=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE
Content-ID: <[email protected]>


(note: the general instance-of such as Module#=3D=3D=3D is transitive in = the=20
sense that it also includes instance-of-subclass-of and so on: every=20
object is an instance-of Object.)

Oh, and I should have added two things:

1. The diagrams that say "instance-of" really mean "direct-instance-of"=20
whereas the other instance-ofs not shown in the diagrams are compositions=
=20
of a subclass-of and instance-of relationship.

2. I'm really beginning to think that if Ruby had had Self's inheritance=20
model (... plus prioritisation of superobjects), it would be so much less=
=20
confusing that, even with all the ruby-talk postings about all the cool=20
things you can do only with Self's inheritance model, it wouldn't nearly=20
reach the level of bandwidth that the current confusion is generating.=20
There's so much more to say about confusing/complicated systems than about=
=20
clean ones, really.

I *think* I've heard Dave Thomas speak against class-oriented object=20
models recently, but haven't heard him elaborate on it though. What I say=
=20
in #2 is only _my_ opinion on the topic.

Of course I can't really expect #2 to happen in this decade, given the=20
amount of opposition I get when I propose *just* merging the Class and=20
Module concepts. Well, unless unexpectedly unexpected changes of heart=20
occur soon enough in the minds of those who are in positions of influence=
=20
wrt Ruby 2.

,-o---------o---------o---------o-. ,----. |
| The Diagram is the Program (TM) | | ,-o----------------------------o-.
`-o-----------------------------o-' | | Mathieu Bouchard (Montr=E9al QC)=
|
| |---' | http://artengine.ca/matju |
| | `-o------------------------------'
---1077017559-1916148283-1114310290=:17345--
---1077017559-1916148283-1114310290=:17345--
 
M

Mathieu Bouchard

---1077017559-2078930741-1114311982=:17345
Content-Type: MULTIPART/MIXED; BOUNDARY="-1077017559-2078930741-1114311982=:17345"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---1077017559-2078930741-1114311982=:17345
Content-Type: TEXT/PLAIN; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE


I'm uneasy with the explanation that "instance_of? doesn't take into=20
account singleton classes", because, as I read it, it seemed to suggest= =20
that what instance_of? returns is irrelevant to the question of whether= =20
or not something is an instance of something else. I'd rather trust the= =20
method; otherwise, I don't know where to start or stop second-guessing=20
the meta-information that Ruby gives me.

I'd call it a bug.

If anyone says that there's no bug in the code of instance_of?,=20
preemptively let me answer that, in that case, the bug is in the naming of=
=20
the method.

Quoting an oft-quoted quote (but which would deserve to be quoted much=20
more often in many more situations):

"You keep using that word.
I do not think it means
what you think it means."
-- Inigo Montoya (in the movie "The Princess Bride")

,-o---------o---------o---------o-. ,----. |
| The Diagram is the Program (TM) | | ,-o----------------------------o-.
`-o-----------------------------o-' | | Mathieu Bouchard (Montr=E9al QC)=
|
| |---' | http://artengine.ca/matju |
| | `-o------------------------------'
---1077017559-2078930741-1114311982=:17345--
---1077017559-2078930741-1114311982=:17345--
 
M

Mathieu Bouchard

---1077017559-1049712057-1114312605=:17345
Content-Type: MULTIPART/MIXED; BOUNDARY="-1077017559-1049712057-1114312605=:17345"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---1077017559-1049712057-1114312605=:17345
Content-Type: TEXT/PLAIN; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE


ah! this is something I always wanted to know, I've been always thinking = on=20
the lines of "why are'nt method just defined in the object? do we need th= is=20
singleton class thing?"

Because of backwards-compatibility with C++/Java/Perl/Python programmers.

Most backwards-compatibility issues occur wrt the _programmers_ and=20
not so much wrt the _programmes_.

,-o---------o---------o---------o-. ,----. |
| The Diagram is the Program (TM) | | ,-o----------------------------o-.
`-o-----------------------------o-' | | Mathieu Bouchard (Montr=E9al QC)=
|
| |---' | http://artengine.ca/matju |
| | `-o------------------------------'
---1077017559-1049712057-1114312605=:17345--
---1077017559-1049712057-1114312605=:17345--
 
M

Mathieu Bouchard

---1077017559-813370389-1114313742=:17345
Content-Type: MULTIPART/MIXED; BOUNDARY="-1077017559-813370389-1114313742=:17345"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---1077017559-813370389-1114313742=:17345
Content-Type: TEXT/PLAIN; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE


* a class is a module which can use inheritance

Module#include qualifies as inheritance, no matter how one may try to hide=
=20
it under a carpet. A dog with a leg missing is still a dog. It doesn't=20
matter how much the Java religion asserts that multiple inheritance is=20
bad. We merely have to assert that multiple inheritance is good, instead=20
of playing word games like what I've consistently heard in the Ruby=20
community in my five years of hanging around. The attempt to attract Java=
=20
programmers to Ruby shouldn't have been done by compromising the=20
simplicity of Ruby; instead it should have been done by cult=20
deprogramming.


The defining qualities of a Ruby class may be that:

1. a Ruby class is a direct-subclass-of a Ruby class using the "<"=20
notation (except the Object class).

2. the Object class just happens to be the place where .new() is defined;=
=20
and this is no matter how many classes use undef_method:)new) to forbid=20
instantiation.

- "birth" class which can create instance
- "singleton" class which is always associated with only one object
and no, a "singleton" class is not a "birth" class.

Btw, are TrueClass, FalseClass and NilClass considered "birth" or=20
"singleton", and then why would they be like that?


,-o---------o---------o---------o-. ,----. |
| The Diagram is the Program (TM) | | ,-o----------------------------o-.
`-o-----------------------------o-' | | Mathieu Bouchard (Montr=E9al QC)=
|
| |---' | http://artengine.ca/matju |
| | `-o------------------------------'
---1077017559-813370389-1114313742=:17345--
---1077017559-813370389-1114313742=:17345--
 
G

gabriele renzi

Mathieu Bouchard ha scritto:
Module#include qualifies as inheritance, no matter how one may try to
hide it under a carpet. A dog with a leg missing is still a dog. It
doesn't matter how much the Java religion asserts that multiple
inheritance is bad. We merely have to assert that multiple inheritance
is good, instead of playing word games like what I've consistently heard
in the Ruby community in my five years of hanging around. The attempt to
attract Java programmers to Ruby shouldn't have been done by
compromising the simplicity of Ruby; instead it should have been done by
cult deprogramming.

I disagree, thinking that mixins and multiple inheritance are not the
same thing, and should not be pointed as such.
The defining qualities of a Ruby class may be that:

1. a Ruby class is a direct-subclass-of a Ruby class using the "<"
notation (except the Object class).

2. the Object class just happens to be the place where .new() is
defined; and this is no matter how many classes use undef_method:)new)
to forbid instantiation.

Is'nt it Class#new ?
 
G

gabriele renzi

Mathieu Bouchard ha scritto:
Because of backwards-compatibility with C++/Java/Perl/Python programmers.

Most backwards-compatibility issues occur wrt the _programmers_ and not
so much wrt the _programmes_.

I don't understand, sorry.
Python programmers for sure can define singleton methods directly in a
object without singleton classes, I guess perl folks too, since an
object is mostly an hash (I may be wrong, not really good at perl).
Actually, only Java's anonymous classes seem somewhat similar to
singleton ones.

I agree with you that some backward compatibility issues may be
programmer-based, but I don't think this is a case.
 
D

David A. Black

Hi --
Because of backwards-compatibility with C++/Java/Perl/Python
programmers.

Is this something you have real reason stood behind Matz's design
decisions, or is it just an unkind jab at a design you don't happen to
like?


David
 
M

Mathieu Bouchard

---1077017559-192036790-1114352737=:32332
Content-Type: MULTIPART/MIXED; BOUNDARY="-1077017559-192036790-1114352737=:32332"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---1077017559-192036790-1114352737=:32332
Content-Type: TEXT/PLAIN; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE


Mathieu Bouchard ha scritto:
Python programmers for sure can define singleton methods directly in a ob= ject=20
without singleton classes,

I avow I don't know enough Python for that.
I guess perl folks too, since an object is mostly=20
an hash (I may be wrong, not really good at perl).

No: in Perl, a hash can contain anonymous subs (that is like Ruby procs),=
=20
but the method lookup is a different thing. For example, suppose you have=
=20
a variable $x holding a pointer to an object that is made out of a hash.=20
Then calling a proc that is an instance variable will look like:

$x->{hello}();

and that is also valid syntax for calling an anonymous sub in any Perl=20
hash, even if it doesn't have a class attached to it. But that mechanism=20
does not support inheritance at all. What is called a method-call in Perl=
=20
is:

$x->hello;

where hello is a _named_ sub in the package that has been assigned to the=
=20
$x hash using the bless() builtin.

In Ruby, this is the same difference as between those two expressions:

x.foo
x.instance_eval{@foo}[]

and clearly the latter isn't calling a method foo in x, and can't perform=
=20
anything inheritance-related either.
Actually, only Java's anonymous classes seem somewhat similar to singleto= n=20
ones.

They are not. They are a special case of inner classes, and inner classes=
=20
blend the concepts of class, delegation, and closure, all together, but=20
nothing in Java is singleton. But still I am curious: could you please=20
provide a snippet in which you emulate singleton behaviour using Java's=20
anonymous classes?



,-o---------o---------o---------o-. ,----. |
| The Diagram is the Program (TM) | | ,-o----------------------------o-.
`-o-----------------------------o-' | | Mathieu Bouchard (Montr=E9al QC)=
|
| |---' | http://artengine.ca/matju |
| | `-o------------------------------'
---1077017559-192036790-1114352737=:32332--
---1077017559-192036790-1114352737=:32332--
 
M

Mathieu Bouchard

---1077017559-1125945308-1114353337=:32332
Content-Type: MULTIPART/MIXED; BOUNDARY="-1077017559-1125945308-1114353337=:32332"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---1077017559-1125945308-1114353337=:32332
Content-Type: TEXT/PLAIN; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE


Mathieu Bouchard ha scritto:
I disagree, thinking that mixins and multiple inheritance are not the sam= e=20
thing, and should not be pointed as such.

Take a look at the inheritance mechanism in CommonLISP and how the=20
(call-next-method) macro works in LISP and then you won't be able to=20
honestly tell me that mixins are not inheritance and that Ruby's mixins=20
aren't like Lisp's classes. Really. Go see for yourself.
Is'nt it Class#new ?

Sorry, yes. But it amounts to the same thing, because the (Object)=20
metaclass is the sole direct descendant of Class, and the creation of a=20
new class never can add a new direct descendent to Class, and so it would=
=20
be possible to unify the (Object) metaclass and the Class class and=20
frankly no-one would notice.

Guy Decoux and you are right on this detail, but this detail is not=20
important in my point, and here is what I mean: I mean that what makes a=20
class a class is that it inherits from whatever is the sole authority for=
=20
making new objects, and that's something that non-class modules don't have=
=20
access to.

(And although there *are* some pieces of code that might construct new=20
objects without the help of Class#new, it isn't the one you can use for=20
building objects of your own custom-designed non-singleton classes)

Does that clear up things a bit?

,-o---------o---------o---------o-. ,----. |
| The Diagram is the Program (TM) | | ,-o----------------------------o-.
`-o-----------------------------o-' | | Mathieu Bouchard (Montr=E9al QC)=
|
| |---' | http://artengine.ca/matju |
| | `-o------------------------------'

---1077017559-1125945308-1114353337=:32332--
---1077017559-1125945308-1114353337=:32332--
 
M

Mathieu Bouchard

---1077017559-668567649-1114355740=:32332
Content-Type: MULTIPART/MIXED; BOUNDARY="-1077017559-668567649-1114355740=:32332"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---1077017559-668567649-1114355740=:32332
Content-Type: TEXT/PLAIN; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE


Is this something you have real reason stood behind Matz's design
decisions, or is it just an unkind jab at a design you don't happen to
like?

Ok, I'll try to clear some things up...

I seem to detect an assumption that being backwards-compatible with=20
programmers of more classic languages is something that is negative.

I *haven't* said that.

Maybe the "backwards" word is loaded with negative connotations... but so=
=20
is every other word, given a certain set of expectations on what could be
meant.

It's "backwards" in the sense of just "older", "predating", ... and not in=
=20
the sense of (insert insult here).

One could happily continue using just classes -- and I am still coding in=
=20
a 99% class style, and not going to change anytime soon.

In related news, a lot of people are still using C using techniques of 30=
=20
years ago, and the programs written that way work, and take a large part=20
of making the planet run, and those programs may even be reasonably=20
readable and adaptable, no matter how much the fashion has switched=20
towards class-based programming in the last 15 years. (!) Though surely=20
OOP is not "fashion" in the same way that platform-boots are: there is=20
actually a strong objective advantage to it, but it's just that it doesn't=
=20
show up in all situations, and that the teaching and understanding of how=
=20
to take advantage of OOP hasn't propagated to 100% of the industry yet...=
=20
just like any other piece of knowledge.

However, in Ruby, the design suggests that we're putting a foot in the=20
realm of object-based (in the sense of "prototype"-based) programming, but=
=20
only on top of a more classic design. In retrospect it might have been a=20
good idea to just jump into the prototype-based system beforehand, and=20
then implement a classic class-based system on top of it, akin to what the=
=20
standard libraries of most prototype-based languages are already doing=20
anyway. It probably wasn't something that was that obvious when Ruby was=20
created (and frankly, back then in 1995, *I* didn't know any other OOP=20
than C++).

Adding prototype-like behaviour on top of a class-based system is=20
something interesting, and an idea that was worth trying, but seeing how=20
much head-scratching it generates in ruby-talk, compared to the amount of=
=20
advantage that can be extracted from the concept, I'm now thinking that=20
maybe it wasn't a good idea after all -- and, I repeat, it's not something=
=20
that was much foreseeable 10 years ago, which is why the experiment was=20
worth trying in the first place.

Does that pretty much eliminate the "unkind jab" hypothesis?

Of a more general interest about discussing concepts:

It isn't often that I just like or dislike a programming technique just=20
out of a whim, and when I do, I slap my hand, call myself stupid, and=20
correct the shituation. However I alternately am perceived as too terse=20
and too verbose and it seems like there's no middle ground, but that might=
=20
be because there is no other way to explaining ideas that are not already=
=20
commonplace, than to get long-winded about them. Sometimes I make the=20
mistake of writing something in koan style, but the catch is that the koan=
=20
style is only good for reminding, and not to teach.

Does that clear things up?

,-o---------o---------o---------o-. ,----. |
| The Diagram is the Program (TM) | | ,-o----------------------------o-.
`-o-----------------------------o-' | | Mathieu Bouchard (Montr=E9al QC)=
|
| |---' | http://artengine.ca/matju |
| | `-o------------------------------'
---1077017559-668567649-1114355740=:32332--
---1077017559-668567649-1114355740=:32332--
 
G

gabriele renzi

Mathieu Bouchard ha scritto:
Take a look at the inheritance mechanism in CommonLISP and how the
(call-next-method) macro works in LISP and then you won't be able to
honestly tell me that mixins are not inheritance and that Ruby's mixins
aren't like Lisp's classes. Really. Go see for yourself.


I'm not much into CLOS, but IIRC the basic approach is to linearize the
ancestors (not thinking of MOP, method combination and so on).
I can agree this yields similar result to our mixin strategy, but I fail
to see how it shows mixins are MI.
It would at best show that CLOS' MI is similar to ruby's mixins.
If I would talk about how Eiffel or C++ handle the problem differently
would that prove my they MI!=mixins, or would show that CL has not MI or
simply that there are diferent approaches to the problem?

You snipped out (or I misquoted it) the part I was actually referring:

The core idea of MI (to me) is the ability to inherit two things that
would need to be instantiated, while using mixins this is impossible.
And a man with big ears do not qualify as a rabbit to me .

Sorry, yes. But it amounts to the same thing, because the (Object)
metaclass is the sole direct descendant of Class, and the creation of a
new class never can add a new direct descendent to Class, and so it
would be possible to unify the (Object) metaclass and the Class class
and frankly no-one would notice.

Guy Decoux and you are right on this detail, but this detail is not
important in my point,

neither was in mine, just a note :)
and here is what I mean: I mean that what makes a
class a class is that it inherits from whatever is the sole authority
for making new objects, and that's something that non-class modules
don't have access to.

(And although there *are* some pieces of code that might construct new
objects without the help of Class#new, it isn't the one you can use for
building objects of your own custom-designed non-singleton classes)

Does that clear up things a bit?

I think I understood this, *this* is what I think as the difference
beetween mixins and MI :)
 
G

gabriele renzi

Mathieu Bouchard ha scritto:
No: in Perl, a hash can contain anonymous subs (that is like Ruby
procs), but the method lookup is a different thing.

<snip>

sorry, I did not intend that you could handle they the same way.
I was justthinking that in python an object is basically an hash
(actually visible from it's __dict__ attribute) and that there is some
magic for the calling.
Since I recall that perl's OO was inspired from python I was *guessing*
there could be a similar mechanic.

They are not. They are a special case of inner classes, and inner
classes blend the concepts of class, delegation, and closure, all
together, but nothing in Java is singleton. But still I am curious:
could you please provide a snippet in which you emulate singleton
behaviour using Java's anonymous classes?

I was thinking of:

Object a= new Object() {
public String toString(){
return "method ovverriden for this single object";
}
};
System.out.println(a); // => method ovverriden for this single object

like in ruby lookup happens like:
- loon in singleton class
- then in superclasses
in java the lookup becomes
- look in anonymous class
- then in its superclasses
 

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,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top