Add Array#first= and Array#last= to std lib

R

Robert Klemme

2007/12/28 said:
Hi, Robert,

In this case, I think the best way for you is to do it by yourself.
You can override an existing class in Ruby, even the one is a standard
library class.

I am aware of that, thanks. The whole point of this discussion was to
find out whether there are serious reasons why one should not have
this in the standard lib. Array#first and #last *are* in the standard
lib already and at the moment I do not see any reason why Array#first=
and Array#last= should not be.

Kind regards

robert
 
S

Sebastian Hungerecker

Robert said:
bbiker said:
There's is no need for Array#last= or Array#first=
since you can simply use an_array[-1] += 1 or an_array[0] += 1

There is no need for Array#last or Array#first
since you can simply use an_array[-1] or an_array[0]

With the same argument you can throw out a lot of library methods
because there is "no need" for them. I do not count that as an argument
against.

I'm not quite sure whether you're talking to bbiker or me, but if you're
talking to me:
Yes, that was the point I was trying to make. I'm on your side, remember?
(Well, mostly anyway)
 
S

Sebastian Hungerecker

Robert said:
I do not see why allowing last= would make lasts(n)= necessary.

For consistency. I believe that any method foo= should be equivalent to the
method foo except for the fact that it sets the value instead of getting it,
which in this case isn't possible (without changing the language). I mean,
that's not a major problem, but it'd feel a tad incosistent to me.
 
S

Sebastian Hungerecker

Robert said:
So far the only argument against I have seen so far is the question
about assignment to an empty array. =A0In that case I'd say, either raise
an exception or silently add the element. =A0Have to think about this a b=
it.

I really don't think that's much of an argument. Since last=3D would be=20
equivalent to [-1]=3D in every other case, it should behave like it in
this case as well (meaning raise an exception) and if last=3D uses []=3D
(which I assume, it would) that would automatically be the case anyway.


=2D-=20
Jabber: (e-mail address removed)
ICQ: 205544826
 
R

Robert Klemme

2007/12/28 said:
For consistency. I believe that any method foo= should be equivalent to the
method foo except for the fact that it sets the value instead of getting it,
which in this case isn't possible (without changing the language). I mean,
that's not a major problem, but it'd feel a tad incosistent to me.

You're right. Actually I was not aware that you could actually use an
argument with last. Thanks for pointing that out!

And I agree, that changes the situation a bit. As a workaround you
could implicitly use the number of elements when assigning an Array
but I doubt it's a good idea. What if you wanted the last element to
be that array and not replace the last n elements? That situation
could not be distinguished. Hm...

Re your other posting: yes, making last= behave like [-1]= is
certainly a good idea. So it's "throw an exception".

irb(main):004:0> a=[]
=> []
irb(main):005:0> a[-1]=123
IndexError: index -1 out of array
from (irb):5:in `[]='
from (irb):5
from :0

Also a tad inconsistent:

irb(main):006:0> a[0]=123
=> 123
irb(main):007:0> a
=> [123]

So at least I now have an idea why last= is absent from the std lib.
So the discussion was definitively worthwhile.

Kind regards

robert
 
T

Trans

You're right. Actually I was not aware that you could actually use an
argument with last. Thanks for pointing that out!

And I agree, that changes the situation a bit. As a workaround you
could implicitly use the number of elements when assigning an Array
but I doubt it's a good idea. What if you wanted the last element to
be that array and not replace the last n elements? That situation
could not be distinguished. Hm...
So at least I now have an idea why last= is absent from the std lib.
So the discussion was definitively worthwhile.

I see it from a different pov: Wasted Semantics. Regardless of the
fact that #first and #last can take an _optional_ argument, #first=
and #last= are both semantically obvious and would take up essentially
no new space in the ruby "dictionary" (to use a Forth term). So, NOT
having them is a waste of resources.

Also, it's not inconceivable that they could provide some added value
by being different form [0], [-1] by not throwing an error.

T.
 
R

Robert Dober

George wrote:
What would you expect this to do?
[].last = 1
The same thing as "[][-1] = 1", I'd imagine.
The problem I'm seeing would be this: If you allow arr.last = x, you'd also
have to allow arr.last(n) = x if you want to be consistent, but that's not
syntactically possible.

Agree. It's tempting to treat #first / #last as 0 / -1, but in
actuality they are method calls and simply return a value; they don't
subscript an array. Setting #last is not semantically different than
[1,2,3].pop = 4, it's just that #last is just a bit more subtle.

I don't see what you are getting at here. #pop is destructive, #last
is not. What does #last return when it is called? It returns a
reference to the last element. So why would #last= do anything other
then set the reference of the last element? Seems obvious to me. So we
can't do last(n) = x, due to syntax constraints, oh well. It would
still be convenient to have the obvious n=1, no arg case. I find that
my programs are usually easier to read when I can use words rather non-
alphabetic symbols.

T.
Amen, big +1, I guess lots of us define #last= and #first=, I do it,
it is just that readable and I did not even check the
doc before trying to use it first, I hate to be disappointed by my
favorite language ;)

Cheers
Robert
 
B

bbiker

For consistency. I believe that any method foo= should be equivalent to the
method foo except for the fact that it sets the value instead of gettingit,
which in this case isn't possible (without changing the language). I mean,
that's not a major problem, but it'd feel a tad incosistent to me.

You're right. Actually I was not aware that you could actually use an
argument with last. Thanks for pointing that out!

And I agree, that changes the situation a bit.  As a workaround you
could implicitly use the number of elements when assigning an Array
but I doubt it's a good idea.  What if you wanted the last element to
be that array and not replace the last n elements?  That situation
could not be distinguished. Hm...

Re your other posting: yes, making last= behave like [-1]= is
certainly a good idea.  So it's "throw an exception".

irb(main):004:0> a=[]
=> []
irb(main):005:0> a[-1]=123
IndexError: index -1 out of array
        from (irb):5:in `[]='
        from (irb):5
        from :0

Also a tad inconsistent:

irb(main):006:0> a[0]=123
=> 123
irb(main):007:0> a
=> [123]

So at least I now have an idea why last= is absent from the std lib.
So the discussion was definitively worthwhile.

Kind regards

robert

I mho, making #last= and #first= adds nothing to ruby, the ability is
already available. So why bloat ruby unnecessarily?
 
M

MonkeeSage

MonkeeSage said:
MonkeeSage wrote:
IOW, #pop returns a value, and this is just what #last does.
How is [] different in that regard? That only returns a value, too.
Exactly. It's not... [] = 3 => syntax error...

That [] there is an emtpy array. That's not the [] I was talking about.
I'm sorry if I wasn't clear, let me rephrase:
You seemed to say that while there is a method Array#[]= (which I assume,
you're ok with, since you haven't stated otherwise), there shouldn't be a
method Array#last= since Array#last only returns a value like Array#pop does.
Now my question to you is: How is Array#[] different in that regard than
Array#last? I mean some_array[-1] also only returns a value. But you don't
have a problem with people being able to write some_array[-1] = some_value
do you?

Sebastian (and Robert),

I guess I wasn't being very clear. By saying that #last just returns a
value like #pop, my point was that #last is the semantic equivalent of
the example I gave: "def l(a); a[-1]; end". I should have probably
compared it to #length rather than #pop since #pop is destructive.

I wasn't arguing for or against #last=, per se; I was only trying to
explain why it doesn't make sense, _to me_, "Unless the semantics [of
#last] change," to have #last=. I.e., #[] subscripts the array and
returns the value of the index, but #last returns the value of
subscripting the array at index #length-1; it is another level of
abstraction removed from #[]; so with those semantics, #last= would be
like #length= (or #pop=), and you end up with exceptions when the
value is immutable.

Regards,
Jordan
 
G

Gary Wright

I wasn't arguing for or against #last=, per se; I was only trying to
explain why it doesn't make sense, _to me_, "Unless the semantics [of
#last] change," to have #last=. I.e., #[] subscripts the array and
returns the value of the index, but #last returns the value of
subscripting the array at index #length-1; it is another level of
abstraction removed from #[]; so with those semantics, #last= would be
like #length= (or #pop=), and you end up with exceptions when the
value is immutable.


Why do you shift your terminology when talking about last? Using
your terminology but my mental model of arrays:

#[n] subscripts the array with n and returns the value of the index
#[-1] subscripts the array with (length-1) and returns the value of
the index
#last subscripts the array with (length-1) and returns the value of
the index

Why do you rephrase that last case as:

#last returns the value of subscripting the array at index #length-1

Are you suggesting that #last does something distinctly different than
subscripting via -1? If not then it would seem your argument against
last=
would apply just as well to 'array[-1] = x'. Are you suggesting that
element assignment with negative subscripts also don't make sense to
you?

Objections to last= and first= based on redundancy is one thing, but
you seem to be objecting based on semantics and I'm trying to understand
that objection because the semantics seem to be quite natural to me.

Gary Wright
 
M

MonkeeSage

I wasn't arguing for or against #last=, per se; I was only trying to
explain why it doesn't make sense, _to me_, "Unless the semantics [of
#last] change," to have #last=. I.e., #[] subscripts the array and
returns the value of the index, but #last returns the value of
subscripting the array at index #length-1; it is another level of
abstraction removed from #[]; so with those semantics, #last= would be
like #length= (or #pop=), and you end up with exceptions when the
value is immutable.

Why do you shift your terminology when talking about last? Using
your terminology but my mental model of arrays:

#[n] subscripts the array with n and returns the value of the index
#[-1] subscripts the array with (length-1) and returns the value of
the index
#last subscripts the array with (length-1) and returns the value of
the index

Why do you rephrase that last case as:

#last returns the value of subscripting the array at index #length-1

Are you suggesting that #last does something distinctly different than
subscripting via -1? If not then it would seem your argument against
last=
would apply just as well to 'array[-1] = x'. Are you suggesting that
element assignment with negative subscripts also don't make sense to
you?

Objections to last= and first= based on redundancy is one thing, but
you seem to be objecting based on semantics and I'm trying to understand
that objection because the semantics seem to be quite natural to me.

Gary Wright

As I understand it, #last is semantically equivalent to this code:

class Array
def last
self[self.length-1]
end
end

Which means that #last is a specialized form of #[], which means that
it is another level of abstraction removed from #[]. So the result of
#last is the same as #[-1], but the semantics of #last are more like
#length or #pop, which are also a level of abstraction removed from
#[]. Once again, I'm not arguing against #last=, per se, but I fail to
see how it differs at the present time from, for example:

class Array
def foo
self[self.length-1]
end
end

[1,2,3].foo = 25

Or more simply, [1,2,3].length = 20.

Of course, one could implement those methods where they so inclined,
but it would make the semantics of, e.g., #foo and #foo= very
different. In this case of #last / #first, I don't think it is very
confusing to have those different semantics; I was probably being too
much of a stickler for "purism".

Regards,
Jordan
 
R

Robert Klemme

I wasn't arguing for or against #last=, per se; I was only trying to
explain why it doesn't make sense, _to me_, "Unless the semantics [of
#last] change," to have #last=. I.e., #[] subscripts the array and
returns the value of the index, but #last returns the value of
subscripting the array at index #length-1; it is another level of
abstraction removed from #[]; so with those semantics, #last= would be
like #length= (or #pop=), and you end up with exceptions when the
value is immutable.
Why do you shift your terminology when talking about last? Using
your terminology but my mental model of arrays:

#[n] subscripts the array with n and returns the value of the index
#[-1] subscripts the array with (length-1) and returns the value of
the index
#last subscripts the array with (length-1) and returns the value of
the index

Why do you rephrase that last case as:

#last returns the value of subscripting the array at index #length-1

Are you suggesting that #last does something distinctly different than
subscripting via -1? If not then it would seem your argument against
last=
would apply just as well to 'array[-1] = x'. Are you suggesting that
element assignment with negative subscripts also don't make sense to
you?

Objections to last= and first= based on redundancy is one thing, but
you seem to be objecting based on semantics and I'm trying to understand
that objection because the semantics seem to be quite natural to me.

Gary Wright

As I understand it, #last is semantically equivalent to this code:

class Array
def last
self[self.length-1]
end
end

Which means that #last is a specialized form of #[], which means that
it is another level of abstraction removed from #[]. So the result of
#last is the same as #[-1], but the semantics of #last are more like
#length or #pop, which are also a level of abstraction removed from
#[].

I do not understand your talking of "removing a level of abstraction".
Basically, I'd say #first and #last are more abstract than #[] because
they add semantics and they are (or at least could be) built on top of
#[]. You do not have to provide the detail of the index to access.

Then, comparing #[], #first and #last with #length and #pop seems very
strange to me - for different reasons: #length has nothing to do with
element access (which is all #[], #first and #last are about). #pop on
the other hand does deal with element access but it also modifies the Array.
Once again, I'm not arguing against #last=, per se, but I fail to
see how it differs at the present time from, for example:

class Array
def foo
self[self.length-1]
end
end

Ah, I believe I start to see something: you do not seem to recognize #[]
and #[]= as _regular methods_. With the implementation of #foo that you
present above you can not do this assignment:
[1,2,3].foo = 25

Consider this:

irb(main):001:0> class Foo
irb(main):002:1> def last;1;end
irb(main):003:1> end
=> nil
irb(main):004:0> f=Foo.new
=> #<Foo:0x7ff958ec>
irb(main):005:0> f.last
=> 1
irb(main):006:0> f.last = 10
NoMethodError: undefined method `last=' for #<Foo:0x7ff958ec>
from (irb):6
from :0
irb(main):007:0> class Foo
irb(main):008:1> def last=(x) puts "assigned"; end
irb(main):009:1> end
=> nil
irb(main):010:0> f.last = 10
assigned
=> 10

You have to implement #last= in order to be able to do the assignment.
You do not automatically get it for free when defining #last. So #last
corresponds to (or: "can be implemented in terms of") #[] while #last=
corresponds to #[]=. Similarly #last also works with frozen instances
(like #[] does) but #last= does not (like #[]= does not). Does this
make sense?

I do not know your (programming) background but if you think Ruby's
Array is similar to a C array then maybe you should drop that notion
because they are vastly different (note, this does not refer to the
implementation but to how they are used in each language).
Or more simply, [1,2,3].length = 20.

As #length has nothing to do with element access I would expect the
_length_ of the Array to change when assigning to it (e.g. by pruning or
appending nils).
Of course, one could implement those methods where they so inclined,
but it would make the semantics of, e.g., #foo and #foo= very
different. In this case of #last / #first, I don't think it is very
confusing to have those different semantics; I was probably being too
much of a stickler for "purism".

Again, this semantic difference you are talking about is still not clear
to me. The semantic between #last and #last= and #first and #first= I
can see at the moment is the lack of a parameter as has been mentioned:
while you can make #last and #first return a sub array you can only
assign to a single element with the assignment variants. But that seems
ok to me.

Kind regards

robert
 
G

George

Again, this semantic difference you are talking about is still not clear
to me. The semantic between #last and #last= and #first and #first= I
can see at the moment is the lack of a parameter as has been mentioned:
while you can make #last and #first return a sub array you can only
assign to a single element with the assignment variants. But that seems
ok to me.

I think I'm sold on the idea. I don't see the extra semantics of
#first and #last over the standard attribute behavior as a problem
either; the getters are just overloaded with a second meaning.

The only slight weirdness I see in it is that [].first = 1 would raise
an IndexError, which seems odd since it doesn't look like there's any
indexing going on. But I'm not sure what would make more sense, and
it's probably best to keep consistent with #[] anyway.

Regards,
George.
 
M

MonkeeSage

On Dec 29, 2007, at 6:24 PM, MonkeeSage wrote:
I wasn't arguing for or against #last=, per se; I was only trying to
explain why it doesn't make sense, _to me_, "Unless the semantics [of
#last] change," to have #last=. I.e., #[] subscripts the array and
returns the value of the index, but #last returns the value of
subscripting the array at index #length-1; it is another level of
abstraction removed from #[]; so with those semantics, #last= would be
like #length= (or #pop=), and you end up with exceptions when the
value is immutable.
Why do you shift your terminology when talking about last? Using
your terminology but my mental model of arrays:
#[n] subscripts the array with n and returns the value of the index
#[-1] subscripts the array with (length-1) and returns the value of
the index
#last subscripts the array with (length-1) and returns the value of
the index
Why do you rephrase that last case as:
#last returns the value of subscripting the array at index #length-1
Are you suggesting that #last does something distinctly different than
subscripting via -1? If not then it would seem your argument against
last=
would apply just as well to 'array[-1] = x'. Are you suggesting that
element assignment with negative subscripts also don't make sense to
you?
Objections to last= and first= based on redundancy is one thing, but
you seem to be objecting based on semantics and I'm trying to understand
that objection because the semantics seem to be quite natural to me.
Gary Wright
As I understand it, #last is semantically equivalent to this code:
class Array
def last
self[self.length-1]
end
end
Which means that #last is a specialized form of #[], which means that
it is another level of abstraction removed from #[]. So the result of
#last is the same as #[-1], but the semantics of #last are more like
#length or #pop, which are also a level of abstraction removed from
#[].

I do not understand your talking of "removing a level of abstraction".
Basically, I'd say #first and #last are more abstract than #[] because
they add semantics and they are (or at least could be) built on top of
#[]. You do not have to provide the detail of the index to access.

Then, comparing #[], #first and #last with #length and #pop seems very
strange to me - for different reasons: #length has nothing to do with
element access (which is all #[], #first and #last are about). #pop on
the other hand does deal with element access but it also modifies the Array.
Once again, I'm not arguing against #last=, per se, but I fail to
see how it differs at the present time from, for example:
class Array
def foo
self[self.length-1]
end
end

Ah, I believe I start to see something: you do not seem to recognize #[]
and #[]= as _regular methods_. With the implementation of #foo that you
present above you can not do this assignment:
[1,2,3].foo = 25

Consider this:

irb(main):001:0> class Foo
irb(main):002:1> def last;1;end
irb(main):003:1> end
=> nil
irb(main):004:0> f=Foo.new
=> #<Foo:0x7ff958ec>
irb(main):005:0> f.last
=> 1
irb(main):006:0> f.last = 10
NoMethodError: undefined method `last=' for #<Foo:0x7ff958ec>
from (irb):6
from :0
irb(main):007:0> class Foo
irb(main):008:1> def last=(x) puts "assigned"; end
irb(main):009:1> end
=> nil
irb(main):010:0> f.last = 10
assigned
=> 10

You have to implement #last= in order to be able to do the assignment.
You do not automatically get it for free when defining #last. So #last
corresponds to (or: "can be implemented in terms of") #[] while #last=
corresponds to #[]=. Similarly #last also works with frozen instances
(like #[] does) but #last= does not (like #[]= does not). Does this
make sense?

I do not know your (programming) background but if you think Ruby's
Array is similar to a C array then maybe you should drop that notion
because they are vastly different (note, this does not refer to the
implementation but to how they are used in each language).
Or more simply, [1,2,3].length = 20.

As #length has nothing to do with element access I would expect the
_length_ of the Array to change when assigning to it (e.g. by pruning or
appending nils).
Of course, one could implement those methods where they so inclined,
but it would make the semantics of, e.g., #foo and #foo= very
different. In this case of #last / #first, I don't think it is very
confusing to have those different semantics; I was probably being too
much of a stickler for "purism".

Again, this semantic difference you are talking about is still not clear
to me. The semantic between #last and #last= and #first and #first= I
can see at the moment is the lack of a parameter as has been mentioned:
while you can make #last and #first return a sub array you can only
assign to a single element with the assignment variants. But that seems
ok to me.

Kind regards

robert

I guess I still wasn't being clear (hey, I'm trying!). I understand
that you don't get a setter, #foo=, just by defining #foo; and I
realize that #[] and #[]= are methods like any other method. I surmise
that further attempts to explain my reasoning will only serve to
further muddy the water, so I'll withdraw my statements. I have no
real problem with #last= / #first=. I was more talking about
theoretical "purity" than practical application. But I think that with
ruby pragmatism is the rule; just ignore my previous comments. :)

Regards,
Jordan
 
R

Robert Klemme

On Dec 29, 2007, at 6:24 PM, MonkeeSage wrote:
I wasn't arguing for or against #last=, per se; I was only trying to
explain why it doesn't make sense, _to me_, "Unless the semantics [of
#last] change," to have #last=. I.e., #[] subscripts the array and
returns the value of the index, but #last returns the value of
subscripting the array at index #length-1; it is another level of
abstraction removed from #[]; so with those semantics, #last= would be
like #length= (or #pop=), and you end up with exceptions when the
value is immutable.
Why do you shift your terminology when talking about last? Using
your terminology but my mental model of arrays:
#[n] subscripts the array with n and returns the value of the index
#[-1] subscripts the array with (length-1) and returns the value of
the index
#last subscripts the array with (length-1) and returns the value of
the index
Why do you rephrase that last case as:
#last returns the value of subscripting the array at index #length-1
Are you suggesting that #last does something distinctly different than
subscripting via -1? If not then it would seem your argument against
last=
would apply just as well to 'array[-1] = x'. Are you suggesting that
element assignment with negative subscripts also don't make sense to
you?
Objections to last= and first= based on redundancy is one thing, but
you seem to be objecting based on semantics and I'm trying to understand
that objection because the semantics seem to be quite natural to me.
Gary Wright
As I understand it, #last is semantically equivalent to this code:
class Array
def last
self[self.length-1]
end
end
Which means that #last is a specialized form of #[], which means that
it is another level of abstraction removed from #[]. So the result of
#last is the same as #[-1], but the semantics of #last are more like
#length or #pop, which are also a level of abstraction removed from
#[].
I do not understand your talking of "removing a level of abstraction".
Basically, I'd say #first and #last are more abstract than #[] because
they add semantics and they are (or at least could be) built on top of
#[]. You do not have to provide the detail of the index to access.

Then, comparing #[], #first and #last with #length and #pop seems very
strange to me - for different reasons: #length has nothing to do with
element access (which is all #[], #first and #last are about). #pop on
the other hand does deal with element access but it also modifies the Array.
Once again, I'm not arguing against #last=, per se, but I fail to
see how it differs at the present time from, for example:
class Array
def foo
self[self.length-1]
end
end
Ah, I believe I start to see something: you do not seem to recognize #[]
and #[]= as _regular methods_. With the implementation of #foo that you
present above you can not do this assignment:
[1,2,3].foo = 25

Consider this:

irb(main):001:0> class Foo
irb(main):002:1> def last;1;end
irb(main):003:1> end
=> nil
irb(main):004:0> f=Foo.new
=> #<Foo:0x7ff958ec>
irb(main):005:0> f.last
=> 1
irb(main):006:0> f.last = 10
NoMethodError: undefined method `last=' for #<Foo:0x7ff958ec>
from (irb):6
from :0
irb(main):007:0> class Foo
irb(main):008:1> def last=(x) puts "assigned"; end
irb(main):009:1> end
=> nil
irb(main):010:0> f.last = 10
assigned
=> 10

You have to implement #last= in order to be able to do the assignment.
You do not automatically get it for free when defining #last. So #last
corresponds to (or: "can be implemented in terms of") #[] while #last=
corresponds to #[]=. Similarly #last also works with frozen instances
(like #[] does) but #last= does not (like #[]= does not). Does this
make sense?

I do not know your (programming) background but if you think Ruby's
Array is similar to a C array then maybe you should drop that notion
because they are vastly different (note, this does not refer to the
implementation but to how they are used in each language).
Or more simply, [1,2,3].length = 20.
As #length has nothing to do with element access I would expect the
_length_ of the Array to change when assigning to it (e.g. by pruning or
appending nils).
Of course, one could implement those methods where they so inclined,
but it would make the semantics of, e.g., #foo and #foo= very
different. In this case of #last / #first, I don't think it is very
confusing to have those different semantics; I was probably being too
much of a stickler for "purism".
Again, this semantic difference you are talking about is still not clear
to me. The semantic between #last and #last= and #first and #first= I
can see at the moment is the lack of a parameter as has been mentioned:
while you can make #last and #first return a sub array you can only
assign to a single element with the assignment variants. But that seems
ok to me.

I guess I still wasn't being clear (hey, I'm trying!). I understand
that you don't get a setter, #foo=, just by defining #foo; and I
realize that #[] and #[]= are methods like any other method. I surmise
that further attempts to explain my reasoning will only serve to
further muddy the water, so I'll withdraw my statements.

Oh no, please don't do that! Now I will be wandering about for the rest
of the year like a bewitched ghost and wondering what it was that you
tried to convey... ;-)
I have no
real problem with #last= / #first=. I was more talking about
theoretical "purity" than practical application. But I think that with
ruby pragmatism is the rule; just ignore my previous comments. :)

That'll be harder than it looks like. :) Well, maybe with a new year
at hand you might change your mind and take a fresh start at this. At
least I for one would be interested in learning what it was that you
were aiming at.

Kind regards

robert
 

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

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top