DEV Community

Benchmarked new perl class feature with many class builders[2024-06-10 updated]

kobaken on August 12, 2023

[Updated] (2024-06-10 11:13 JST) update to v5.40 benchmarked result GitHub - kfly8/bench-perl-class-builder at v5.40 (2023-08-22 21:30...
Collapse
 
bbrtj profile image
bbrtj

Thanks for the benchmarks. Your Moose case for constructor is flawed, as you didn't make the class meta immutable: metacpan.org/dist/Moose/view/lib/M...

Also, I would suggest having at least a couple of fields in your class. Having just one may favor some simpler solutions which may not scale well. In my own benchmarks it seemed like Moo constructor did not scale as good as Moose one, while being faster for super simple cases.

Collapse
 
kfly8 profile image
kobaken

Thanks for your comment!

I agree that Moose (and also Mouse) would be better if they were immutable.
And you are right, I think the benchmark would be better if it handled cases where the fields are complex.

I would be happy to send me a pull request!

Collapse
 
kfly8 profile image
kobaken

Thanks for your pull requests! I updated this post and repository.

Collapse
 
leonerd profile image
Paul Evans

Something to keep in mind with the field access benchmarks is that the very design of Object::Pad and the core class system offers direct access to the fields of the object to the class's own methods, as simple lexicals. Code inside methods does not have to use the accessors just to see or modify those values. This is a feature unique to those two systems.

Therefore, in real-world code scenarios, the faster more-direct access these provide means that overall code can run faster in a way that simple benchmarks "from outside the class" such as your bench-field.pl do not manage to capture. It would not be easily possible to write a "universal" test case in the same style as your scripts to demonstrate this, exactly because of this unique ability.

As an example, consider this silly class:

class RGBColour {
  field $red :param;
  field $green :param;
  field $blue :param;

  method as_css () {
    sprintf "rgb(%f%%,%f%%,%f%%)", $red, $green, $blue;
  }
}
Enter fullscreen mode Exit fullscreen mode

The ->as_css method here has direct access to the $red, $green and $blue lexicals, and so invoking that would only involve one actual method call at runtime. Whereas, this class based on any of the other systems would need code something like:

sub as_css ($self) {
  sprintf ..., $self->red, $self->green, $self->blue;
}
Enter fullscreen mode Exit fullscreen mode

and thus any call to the outer method would involve three inner calls, a total of four. Once you get into real-world scenarios with code that contains real-world behaviour, the cost of all these little inner $self->field accessor calls quickly adds up and overtakes the original cost of the outside method call or even the object constructor.

Perhaps you could add a new category of benchmark, one that constructs an object with a few nontrivial fields and then performs a calculation method based on the values of those fields - feel free to steal my example code above if it helps. I'd be very interested to see benchmarks of that kind of case too.

Collapse
 
kfly8 profile image
kobaken

Thanks for your kind comments!

I will try the new benchmark case!

Collapse
 
dkechag profile image
Dimitrios Kechagias

It's interesting to see Mouse still leading the pack of the Moose compatible crowd. We switched to it a few years ago after benchmarking, and we've kept it even though Moo became more popular. It even manages to pull a win over the current version of class, but the latter is sure looking good otherwise, especially for something newly added to core!

Collapse
 
kfly8 profile image
kobaken

As you say, by far the best performing accessor was Mouse. I think the difference is whether the accessor works with XS or not. class feature will be adding a :reader modifier in the future that will make the accessor live, and I will try to benchmark it again when that is added.

Collapse
 
bmeneg profile image
Bruno Meneguele

Hey, really nicely done! Hope we can keep this benchmark alive as long as possible!

One suggestion: it would be really nice to keep a "history" graph to follow core class enhancements in future Perl versions. AFAIK only the MVP was introduced to the core, but many optimizations are still to be done, including (as you mentioned in one of your comments) :reader and :writer accessors and, possibly, many other low-level object handling optimizations. So I really expect to see core class feature numbers to decrease, but who knows right? :D

Collapse
 
kfly8 profile image
kobaken

Thank you for your comment!

You are right, it would be nice to keep a history! I look forward to following future Perl updates.

Collapse
 
esabol profile image
Ed Sabol

Very nice!

Collapse
 
chrisarg profile image
chrisarg

Thanks for the update.
Seems the implementation is catching up to blessed hash references.
What about inside out objects classes such as Class:Std, DIOS etc ?

Collapse
 
kfly8 profile image
kobaken

Thank you for your comment! I would be happy if you could send me a pull request!