Proc / def / yield semantics (long)

M

Markus

ABSTRACT

The semantics of Proc object calling was changed between 1.8.0 and
1.8.1 to resolve a disparity with the semantics of yield(); I feel this
was a mistake & would like to see the change reversed. Specifically:

* For 1.8.2 I would like to see the semantics revert to the way
they were in 1.8.0; this leaves the disparity between yield and
Proc#call, but does not break anything.

* For 2.0 I would like the semantics to be homogenized, either by:

* Changing yield (and assignment) to match the semantics
of the rest of the language,
or
* Making the behavior controllable by the user (on a case
by case basis) so that people who want the new behavior
can get it.


BACKGROUND

Ruby supports parallel assignment and array expansion with
relatively clean semantics. Arrays used as the last rvalue or the last
lvalue can be expanded by prefixing them with an "*"; the only
inconsistency come from the fact that:

This is not necessary if the rvalue is the only thing on the
right hand side--the array will be expanded automatically.
-- (Pickaxe I, page 77)

This syntactic "shortcut" can lead to some decidedly unobvious
behavior. For example, adding a rvalue to the right hand side of an
assignment statement can cause the class of any of the other lvalues to
change, but only under some conditions:

x = [1]

a,b = x
p a.class #Fixnum

a,b = x,4
p a.class #Array

x = "1"

a,b = x
p a.class #String

a,b = x,4
p a.class #String

In 1.8.0, only assignment and yield, of the half dozen or so ways
to assign values to a collection of variables, special case single
rvalues which happen to be arrays this way. (The code in listing one
can be used to test the behavior of the different version.)

In the case of assignment, the "feature" is of very slight utility,
since the same effect can be had (if desired) by prefixing the single
rvalue with an "*".

Where it is must useful is in the case of yield, where it
facilitates constructs such as:

my_hash.each { |key,value| ... }

which are widely used.

THE CHANGE

A consequence of this is that using yield on a block has different
semantics than converting the block to a Proc and calling it (as noted
in http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/21726):

def foo
yield([:key, :value])
end
foo {|k, v| p [k, v]} #[:key, :value]

def bar(&blk)
blk.call([:key, :value])
end
bar {|k, v| p [k, v]} #[[:key, :value], nil]


I am somewhat hampered by my illiteracy (at best I can "read"
Japanese at a rate of 1 page a month or so, given sufficient reference
materials) and therefore I am guessing in what follows.

There are two ways that the discrepancy could be resolved: either
the behavior of yield could be changed, or that of Proc#call. If the
former path had been taken, we would have:


def foo
yield([:key, :value])
end
foo {|k, v| p [k, v]} #[[:key, :value], nil]

def bar(&blk)
blk.call([:key, :value])
end
bar {|k, v| p [k, v]} #[[:key, :value], nil]

and the prior behavior could have been reproduced (if desired) by writing:

def foo
yield(*[:key, :value])
end
foo {|k, v| p [k, v]} #[:key, :value]

or more simply (in the example case at least):

def foo
yield:)key, :value)
end
foo {|k, v| p [k, v]} #[:key, :value]

(This is the choice I would have advocated had I been following the
debate. But I wasn't and so I am making this 11th hour plea.)

Instead, it was decided to change Proc. This, I surmise, led to
some problems and a compromise appears to have been hammered out along
these lines (using the tags from the program in listing 1):

inline: special case single arrays
inline (array): no special casing
def: no special casing
Proc.new: special case single arrays
proc: no special casing
My_proc.new: special case single arrays
my_proc: special case single arrays
yield: special case single arrays

Contrast this with the situation in 1.8.0:

inline: special case single arrays
inline (array): no special casing
def: no special casing
Proc.new: no special casing
proc: no special casing
My_proc.new: no special casing
my_proc: no special casing
yield: special case single arrays

and you will note that:

* Kernel#proc is now almost but not quite a synonym for Proc.new

* It does not appear to be possible to subclass Proc without
getting the special case behavior

* It does not appear to be possible to write "wrapper" Procs (a'la
CLOS) that act like methods

* It does not appear to be possible to define something that works
like Kernel#proc

* The potential for odd behavior noted in the background section
has not gone away; instead, it has spread to many more contexts.

CONSEQUENCES

There is a venerable pattern (dating back decades before we even
called them patterns) for dealing with sequences recursively by at each
stage treating the list as a pair: the first item and the rest of the
list. (CAR/CDR)

Up until 1.8.0 (and, I hope, in 1.8.2 on) it is easy to implement
this pattern in ruby. For example:

def tickle(head,*rest)
head.giggle if head.respond_to? :giggle
tickle(rest) if rest
end

This works, but breaks subtly under the new semantics if you try to
make it an object:

tickeler = Proc.new { |head,*rest|
head.giggle if head.respond_to? :giggle
self.call(rest) if rest
}


Another useful construct that is possible with the old semantics
but not with the new is before methods (borrowed from CLOS):

$observers = {}
class Module
def before(method,&block)
new_name = Symbol.unique(method)
alias_method new_name, method
block_name = Symbol.unique(method)
$observers[block_name] = block
module_eval %{
def #{method}(*args, &block)
$observers[:#{block_name}].
call(self,*args,&block)
#{new_name}(*args,&block)
end
}
return [self, method, new_name, block_name]
end
end

with which we can write:

class Animal
def dinner(...)
:
end
:
end

Animal.before :dinner do |animal,*args|
:
end


Of course, this only works so long as the semantics of calling a
block are the same as the semantics of calling a method. In other
words, it works fine under 1.8.0 but fails mysteriously under 1.8.1

There are many such examples, but most of them are much harder to
abstract (or at least, harder to abstract concisely). For example, the
Action pattern and its kin are much easier to implement if Procs and
methods don't have different special cases.


PROPOSED RESOLUTION

I gather the deadline for 1.8.2 is looming. Therefore, for 1.8.2,
I would propose going back to the 1.8.0 semantics. This could be done
(I believe) by simply reversing the change made by Matz on 30 September
2003. Anyone who wants the new behavior should be able to get it by the
judicious use of "*".

For 2.0 (which, as I understand it, is not committed to 100%
backward compatibility), I would recommend one of the following:

* If no one can devise a case in which it would not be possible to
reproduce the special case behavior by prefixing single rvalues
with an "*", I would recommend eliminating the special case
altogether. This would mean changing the semantics of yield and
assignment slightly, through I would be surprised if there was
much code at all (out side of iterators over structures such as
hashes) that _wants_ the new behavior.

* If there is some reason why yield and assignment need to keep
the special case, I would like to see a flag added to the Proc
object that determines its behavior. Rather than having
Kernal#proc return one type of Proc and Proc#new return a subtly
different type of Proc, both should return the same thing and
its behavior should be adjustable either at creation time (via a
parameter to the creation method) or by sending a message to the
object (Proc#expand_array_parameters=, or some such).



Thank you for taking time to read this; I'm sorry I wasn't alert
enough to offer it a year ago. As always, I am more than willing to
help in whatever way is needed.

-- Markus



LISTING 1

def show(h,r)
print " head: #{h.inspect}, rest: #{r.inspect} "
end


#-----------------------------------------------
print "inline: "
#head,*rest = 1,2,3 ; show(head,rest)
#head,*rest = [1],2,3 ; show(head,rest)
head,*rest = [1,2],3 ; show(head,rest)
head,*rest = [1,2,3] ; show(head,rest)
print "\n"

#-----------------------------------------------
print "inline (array): "
#a = [1,2,3] ; h,*r = *a; show(head,rest)
#a = [[1],2,3] ; h,*r = *a; show(head,rest)
a = [[1,2],3] ; h,*r = *a; show(head,rest)
a = [[1,2,3]] ; h,*r = *a; show(head,rest)
print "\n"

#-----------------------------------------------
print "def: "
def test1(head,*rest)
show(head,rest)
end
#test1(1,2,3)
#test1([1],2,3)
test1([1,2],3)
test1([1,2,3])
print "\n"

#-----------------------------------------------
print "Proc.new: "
test2 = Proc.new { |head,*rest|
show(head,rest)
}
#test2.call(1,2,3)
#test2.call([1],2,3)
test2.call([1,2],3)
test2.call([1,2,3])
print "\n"

#-----------------------------------------------
print "proc: "
test3 = proc { |head,*rest|
show(head,rest)
}
#test3.call(1,2,3)
#test3.call([1],2,3)
test3.call([1,2],3)
test3.call([1,2,3])
print "\n"

#-----------------------------------------------
print "My_proc.new: "
class My_proc < Proc
end
test4 = My_proc.new { |head,*rest|
show(head,rest)
}
#test4.call(1,2,3)
#test4.call([1],2,3)
test4.call([1,2],3)
test4.call([1,2,3])
print "\n"

#-----------------------------------------------
print "my_proc: "
def my_proc(&b)
b
end
test5 = my_proc { |head,*rest|
show(head,rest)
}
#test5.call(1,2,3)
#test5.call([1],2,3)
test5.call([1,2],3)
test5.call([1,2,3])
print "\n"

#-----------------------------------------------
print "yield: "
def test6
#yield(1,2,3)
#yield([1],2,3)
yield([1,2],3)
yield([1,2,3])
end
test6 { |head,*rest|
show(head,rest)
}
print "\n"
 
T

ts

M> * It does not appear to be possible to subclass Proc without
M> getting the special case behavior

svg% cat b.rb
#!/usr/bin/ruby
class A < Proc
def self.new(&block)
proc(&block)
end
end

a = A.new {|a, *b| p a, b }
a.call([1, 2, 3])
svg%

svg% b.rb
[1, 2, 3]
[]
svg%



Guy Decoux
 
B

Brian Candler

I support all that you have written, as I have been bitten by this
inconsistency in the past (in a less serious way than you).

Can I add some simple observations:

(1) When you write a,b = c

then Ruby has to assume you mean either:

(i) a,b = c,nil
or (ii) a,b = *c

In the simple assignment case, both can be achieved explicitly; I guess Ruby
chooses (ii) as "more likely to be what you meant", but you don't actually
need that magic because you can achieve it youself using "*". Similarly for
a = b,c:

(iii) a,dummy = b,c
(iv) *a = b,c

(2) The problem with Hash#each is that for hashes to be enumerable they must
contain a list of individual "things", and a "thing" is chosen here to be a
[key,value] pair.

So Hash#each does yield [k,v]

and the block we pass in takes |thing| as a parameter. Now, we'd like to be
able to do
myhash.each { |key,value| ... }

but we need magic for that. We can't achieve it using "*", because we'd have
to change the 'yield' statement to do that: yield *[k,v], or yield k,v. In
other words, we'd have to modify the source code of the iterator itself.

NOW: if it's *only* Hash#each which is the problem here, then one Ruby-2.0
solution is to add a new iterator to Hash, or just redefine

Hash#each_pair --> yield k,v

This iterator already exists in the language, so you could make your code
backwards-compatibile by using it where you want to do { |key,value| ... }

But it seems to me a better option would be to have a way at the *receiver*
of specifying that you want the argument 'exploded', and it turns out that
Ruby already has this:

myhash.each { |(key,value)| ... }

Tested in 1.8.1:

def foo
yield [1,2], [3,4]
end

foo { |a,b| p a,b }
[1, 2]
[3, 4]
=> nil

foo { |x,(y,z)| p x,y,z }
[1, 2]
3
4
=> nil

So perhaps all we need to do, for ruby-2.0 at least, is keep this mechanism
and get rid of the rule which says "if single argument is an array then
auto-expand it" completely.

And then, maybe we should persuade people to write
(a,b)=c
rather than
a,b=*c

(although exploding at the sender, i.e. "yield *foo" and "bar(*foo)", are
still useful constructs)

Applying this to your example:
There are two ways that the discrepancy could be resolved: either
the behavior of yield could be changed, or that of Proc#call. If the
former path had been taken ...
the prior behavior could have been reproduced (if desired) by writing:

def foo
yield(*[:key, :value])
end
foo {|k, v| p [k, v]} #[:key, :value]

Without changing the definition of foo, you could just have called it as

foo {|(k,v)| p [k, v]} #[:key, :value]


(3) It may be possible to keep Ruby's automagic exploding of arguments, if
we limit it to cases where there is no ambiguity. I am thinking of:

- the sender passes a single array value;
- the receiver REQUIRES two or more arguments.

This is unlike def foo(head,*rest) or proc {|head,*rest| ... }, where it can
take _one_ or more arguments, so the rule would not apply.

This might be a solution for 1.8.2, where you want to be backwards
compatible. At least, Hash#each { |key,value| ... } would continue to work.
But it still wouldn't be consistent, unless you also applied it also to
method calls (which would be dubious, IMO)

Regards,

Brian.
 
T

trans. (T. Onoma)

Kudos.

ABSTRACT

The semantics of Proc object calling was changed between 1.8.0 and
1.8.1 to resolve a disparity with the semantics of yield(); I feel this
was a mistake & would like to see the change reversed. Specifically:

* For 1.8.2 I would like to see the semantics revert to the way
they were in 1.8.0; this leaves the disparity between yield and
Proc#call, but does not break anything.

* For 2.0 I would like the semantics to be homogenized, either by:

* Changing yield (and assignment) to match the semantics
of the rest of the language,
or
* Making the behavior controllable by the user (on a case
by case basis) so that people who want the new behavior
can get it.

[snip]

T.
 
M

Markus

M> * It does not appear to be possible to subclass Proc without
M> getting the special case behavior

svg% cat b.rb
#!/usr/bin/ruby
class A < Proc
def self.new(&block)
proc(&block)
end
end

a = A.new {|a, *b| p a, b }
a.call([1, 2, 3])
svg%

But a.class is Proc, not A.

-- Markus
 
M

Markus

I support all that you have written, as I have been bitten by this
inconsistency in the past (in a less serious way than you).
[snip]
So perhaps all we need to do, for ruby-2.0 at least, is keep this mechanism
and get rid of the rule which says "if single argument is an array then
auto-expand it" completely.

That was my conclusion as well.
(3) It may be possible to keep Ruby's automagic exploding of arguments, if
we limit it to cases where there is no ambiguity. I am thinking of:

- the sender passes a single array value;
- the receiver REQUIRES two or more arguments.

This is unlike def foo(head,*rest) or proc {|head,*rest| ... }, where it can
take _one_ or more arguments, so the rule would not apply.

This might be a solution for 1.8.2, where you want to be backwards
compatible. At least, Hash#each { |key,value| ... } would continue to work.
But it still wouldn't be consistent, unless you also applied it also to
method calls (which would be dubious, IMO)

I played around with this idea (briefly) yesterday before posting.
I reached the (tentative) conclusion that any attempt to retain
auto-explosion and enforce consistency would blow up. The goatch for
this one: if a method required two arguments and was passed an array by
some user, changing the method so that the second argument was optional
would (instead of required) would silently change what was passed in for
the second argument--it would now get the array, and the second would
get the default.

You can move the problem around, but getting rid of implicit array
explosion entirely seems to be the only cure.

-- Markus
 
A

Austin Ziegler

Actually, Markus, your examples don't work in 1.8.2 at all -- neither
the tickl() method or the tickler proc. These do:

def tickle(head, *rest)
head.giggle if head.respond_to? :giggle
tickle(*rest) unless rest.empty?
end

tickler = Proc.new { |head, *rest|
head.giggle if head.respond_to? :giggle
tickler.call(*rest) unless rest.empty?
}

class Giggler
def initialize(pos)
@pos = pos
end

def giggle
puts "#{@pos}: giggle"
end
end

a = []
10.times do |pos|
if (rand < 0.501)
a << Giggler.new(pos)
else
a << Object.new
end
end
p a

tickle(*a)
tickler[*a]

I don't claim to understand the difference, really -- with the
exception of the yield capability in Hash#each, I don't tend to rely
on auto-expansion, instead being explicit.

-austin
 
M

Markus

Actually, Markus, your examples don't work in 1.8.2 at all -- neither
the tickl() method or the tickler proc. These do:

Yes, thanks. I should have included my usual caveat about code
typed directly into a mail message.
with the exception of the yield capability in Hash#each, I don't
tend to rely on auto-expansion, instead being explicit.

That's been my position as well. The problem here being that (as
of 1.8.1) you get auto-expansion whether you want it or not. I don't
object at all to having expansion available in situations where it is
explicitly requested; in fact, I consider it a valuable feature, for
which I am more than happy to pay an "*". But serious semantic tangles
arise when array expansion is automatic and implicit under some
circumstances, with no way to turn it off or even detect that it has
been inflicted upon you.

-- Markus

P.S. I'm starting to question whether it is even needed for Hash#each; I
can see at least two alternative ways to conceptualize the present
behavior of Hash#each (one of which works nicely with the "association"
extension proposed a week or so ago) without using implicit array
expansion at all. If the idea holds up after some food & sleep &
further mulling I'll post the details.
 
B

Brian Candler

...
I played around with this idea (briefly) yesterday before posting.
I reached the (tentative) conclusion that any attempt to retain
auto-explosion and enforce consistency would blow up. The goatch for
this one: if a method required two arguments and was passed an array by
some user, changing the method so that the second argument was optional
would (instead of required) would silently change what was passed in for
the second argument--it would now get the array, and the second would
get the default.

True, but if you change the number of parameters which a (method|proc|block)
expects, then you're almost certain to change the semantics anyway.

In the case I'm thinking of, Ruby would otherwise have raised an
"ArgumentError: wrong number of arguments (1 for 2)". So you're still
changing the semantics by making the second argument optional.

So I believe it's a question of which is more useful: the ArgumentError
(perhaps making it quicker to track bugs due to wrong number of arguments
being passed), or to auto-explode.

Somehow I feel happier retaining this for blocks, for backwards-
compatibility with 1.8.x, than to introduce it for method calls for
consistency:

def foo(a,b)
# ...
end

a = [1,2]
foo(a) # Feels like this *ought* still to raise an ArgumentError

How do people feel about

myhash.each{|key,value| ... }

raising an ArgumentError, forcing you to rewrite it as

myhash.each{|(key,value)| ... }

?

Regards,

Brian.
 
A

Austin Ziegler

How do people feel about

myhash.each{|key,value| ... }

raising an ArgumentError, forcing you to rewrite it as

myhash.each{|(key,value)| ... }

-1

I can't stand the |(...)| notation.

-austin
 
M

Markus

True, but if you change the number of parameters which a (method|proc|block)
expects, then you're almost certain to change the semantics anyway.

No. Consider: you have something (in working code) that accepts
two parameters, and every time it is called, it receives two
parameters. The code, as written, has been well tested and is known to
work.
If you add a default value to the second parameter, for use by
newly written code, you would expect the old code (which always provides
two values) to continue to function correctly. It would, under 1.8.0,
and any other language I can think of that allows for default
parameters.

But if some users were depending on auto-array-explosion under the
semantics proposed above, the old code would silently break; the array
that had auto-expanded when there were two REQUIRED parameters would
quietly stop exploding.
In the case I'm thinking of, Ruby would otherwise have raised an
"ArgumentError: wrong number of arguments (1 for 2)". So you're still
changing the semantics by making the second argument optional.

No, under your proposed semantics it would have otherwise
auto-exploded because:

Somehow I feel happier retaining this for blocks, for backwards-
compatibility with 1.8.x, than to introduce it for method calls for
consistency:

def foo(a,b)
# ...
end

a = [1,2]
foo(a) # Feels like this *ought* still to raise an ArgumentError

I agree.

How do people feel about

myhash.each{|key,value| ... }

raising an ArgumentError, forcing you to rewrite it as

myhash.each{|(key,value)| ... }

My present thinking is that this is a red herring. We've been
talking as if Hash#each perforce uses default auto array explosion,
assuming that it is internally analogous to:

yield(kv_array)

... { |kv| ...
... { |k,v| ...

and thus

kv = kv_array
k,v = kv_array

where the latter case requires auto array explosion.

But:

1. As people have previously pointed out, there is no actual
kv_array; it should, if anything, be a new class (an
Association)
2. Since the array supposedly being exploded is inside the
definition of Hash#each, it would only have to be changed in
this one place (by adding an "*") to make it explicit in any
case.
3. What's really going on is auto IMPLOSION, analogous to:

yield(k0,v0)

... { |kv| ...
... { |k,v| ...

and thus

kv = k0,v0
k,v = k0,v0

...all of which would work exactly as before, even if
auto-explosion was completely eradicated from the language.
(Auto implosion appears to be much less problematic since there
is only one mechanism that I am aware of to pass around lvalue
lists, and no l-side "default destination" analog to default
rvalues).


-- Markus
 
M

Markus

-1

I can't stand the |(...)| notation.

I'm not crazy about it myself, though I suspect my prefered
alternative:

myhash.each {|[key,value]| ... }

may be as objectionable to you. In any case, it appears to be a red
herring (see my response to Brian).

-- Markus
 
B

Brian Candler

No. Consider: you have something (in working code) that accepts
two parameters, and every time it is called, it receives two
parameters. The code, as written, has been well tested and is known to
work.
If you add a default value to the second parameter, for use by
newly written code, you would expect the old code (which always provides
two values) to continue to function correctly. It would, under 1.8.0,
and any other language I can think of that allows for default
parameters.

But if some users were depending on auto-array-explosion under the
semantics proposed above, the old code would silently break; the array
that had auto-expanded when there were two REQUIRED parameters would
quietly stop exploding.

OK, point taken; a quick check confirms you can make optional parameters in
blocks, i.e.
foo { |a,*b| p a,b }

[although not |a,b=nil| like you can have in method definitions]
1. As people have previously pointed out, there is no actual
kv_array; it should, if anything, be a new class (an
Association)
2. Since the array supposedly being exploded is inside the
definition of Hash#each, it would only have to be changed in
this one place (by adding an "*") to make it explicit in any
case.

It's a bit of a pain to fiddle with the internal working of existing
iterators though; you'd have to wrap them something like

class Foo
def exploded_each(*args)
each(*args) { |a| yield *a }
end
end
3. What's really going on is auto IMPLOSION, analogous to:

yield(k0,v0)

... { |kv| ...
... { |k,v| ...

Ah, right. I was assuming Hash#each doing "yield [k,v]", when it seems it
actually does "yield k,v" (yep, looking at each_pair_i in hash.c)

In that case, if it can be imploded into a pair [k,v] automatically for the
purposes of Enumerable, then perhaps you're right, the problem goes away.

In which case, why does auto-explosion happen at all? Can someone provide
some compelling examples where it is needed?

Regarding Associations though: if Hash#each did start returning these, you
would clearly not be able to do

myhash.each { |k,v| ... }

any more. So you'd probably want a new interator for that case:

myhash.each_pair { |k,v| ... } # already exists
or
myhash.each_with_index { |v,k| ... } # like an array

Regards,

Brian.
 
M

Markus

Regarding Associations though: if Hash#each did start returning these, you
would clearly not be able to do

myhash.each { |k,v| ... }

any more. So you'd probably want a new interator for that case:

myhash.each_pair { |k,v| ... } # already exists
or
myhash.each_with_index { |v,k| ... } # like an array

Perhaps. I keep feeling that there is an "Ah ha!" lurking in here
somewhere--if we just look at things on the right way, we could (for
2.0) get nearly full backward compatibility, cleaner semantics, and
nice route for expanded expressiveness. I'll post more if the idea
still seems reasonable after I think on it for a day or so...

-- Markus
 
M

Mark Hubbart

Perhaps. I keep feeling that there is an "Ah ha!" lurking in here
somewhere--if we just look at things on the right way, we could (for
2.0) get nearly full backward compatibility, cleaner semantics, and
nice route for expanded expressiveness. I'll post more if the idea
still seems reasonable after I think on it for a day or so...

If Association is a subclass of Array or Values, then it should be
possible to splat it. Here's an extremely bare-bones version
demonstrating the possible behavior:

class Association < Values
def initialize(key, value)
self.replace [key, value]
end
# a simple formatter for inspections, prints "key => value"
def inspect
map{|item| item.inspect}.join " => "
end
end
==>nil

# Examples:

h.each{|assoc| p assoc} # inspects the associations
:b => 2
:c => 3
:a => 1
==>{:b=>2, :c=>3, :a=>1}
h.each{|(key,val)| puts "key = #{key}, value = #{val}"} # list should
expand
key = b, value = 2
key = c, value = 3
key = a, value = 1
==>{:b=>2, :c=>3, :a=>1}

Note that currently, you don't even have to write |(key,val)|, it will
auto-expand. But I don't think that's future-proof.

It's a neat idea, but I would wonder how practical it would be; I get
the feeling our nice fast hash lookups would be ruined... But since I
don't know the internals...

cheers,
Mark
 
G

Gavin Kistner

#each_pair exists...I never even knew you could throw two params in the
block for #each until recently.

Thus, I don't personally care if it raises an error if you don't wrap
them in parens (although I don't like the |(aaa,bbb)| look) or fails to
work altogether :)
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top