pdl / Test-Proto

OO test script golf sugar
1 stars 1 forks source link

eq, ne, gt, lt, ge, lt, le are all numeric and that's surprising. #32

Closed schwern closed 11 years ago

schwern commented 11 years ago

I was surprised when reading through the code for _cmp that its all numeric. I would expect them to be string comparisons, given how they map directly to the Perl string comparison routines.

If that is changed, IMO it should be, it leaves the unfortunate and common question of what to call the numeric methods... or maybe not. There is a "String" class but no "Number" class. Perhaps there should be.

pdl commented 11 years ago

Been a while since I looked at that code I'll have a look later. But you might want to peruse:

The rationale is that I frequently want to use a comparison function that is neither of these (e.g. case and accent folded dictionary-style comparison) and want to leave that logic open.

Also, you can't stick !<=> in method names.

pdl commented 11 years ago

Ah, yes, ok, so _cmp and all the methods you list require an object or coderef that will do the comparison for you. It is actually agnostic about string vs number. The numeric comparisons you're seeing are in fact comparisons of the return value of the real comparison.

schwern commented 11 years ago

It took me a while to see the value in that. I see what its trying to do, but its not the easiest thing to get one's head around. Especially for the simple cases of string and numeric equality.

How about this instead...

p->cmp($comparison_function => $comparison_type, $value);

For example p->cmp(\&string_cmp => "ge", "a"); to do a ge string comparison with "a". I don't know if that's really any easier.

I almost want to write p->cmp( string_cmp->("eq"), "a" ); so the string_cmp routine curries the comparison operator and returns a new function, but most folks aren't ready for currying and it makes writing comparison routines more difficult.

Maybe...

p->cmp($comparison_function, $comparison_type)->($value);

Then the user can write a simple comparison function, cmp does the currying, and if they want to plug in different values later they can.

my $string_eq = p->cmp(\&string_cmp, "eq");
$string_eq->("foo")->ok($val);
$string_eq->("bar")->ok($val);`
pdl commented 11 years ago

I much prefer the first.

The version after "Maybe..." turns the prototype into a coderef which prepares to add the test to the prorotype... That seems rather roundabout, and also is very different to the approach of all the other test methods.

Normally, you should just be able to add tests sequentially. You really need the value you're comparing it to at the time of adding the test. What if you had two such comparison operators, e.g. I want it to be more than 0 but less than 256?

What you want to do is something of the form p->lt(256)->gt(0)->ok($val).

That is... p->cmp('lt', 256)->cmp('gt', 0)->ok($val).

That is... p->cmp(sub {$a <=> $b}, 'lt', 256)->cmp(sub {$a <=> $b}, 'gt', 0)->ok($val).

Ideally, you also want to not have to include the comparator code each time. But for most cases, that might be a question of making sure you're using Test::Proto::String or Test::Proto::Number accordingly.

The simple things should be easy, and the complex things should not hog the simple-sounding names like gt.

schwern commented 11 years ago

I see your point about the chaining.

I'm itchy about using the proto type (ie. String or Number) to choose the comparison type. This seems like a hidden action which will be difficult to debug. Also you might want to do a string comparison on numbers and vice versa. And it doesn't solve the Scalar problem. I'm still for making it explicit.

Perhaps p->cmp is sub { $a cmp $b }, p->ncmp (numeric cmp) is sub { $a <=> $b } and there's a third method for providing your own routine. p->my_cmp or something.