-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
experiment with named classes in operations #265
Conversation
Yes, thanks! Exactly what I had in mind :) |
@armanbilge how would you recommend measuring/verifying the reduction of code bloat? write some operator invocations and measure .jar size? |
Right, that would probably be the way to do it. Another metric would be to introspect the jars and count the number of class files inside. |
Here's a Cats PR focused on class size. But that was generated sources, not macros. Macros makes it a lot harder. Actually, maybe what you want to measure is not the absolute artifact size, but how it grows. E.g. do more ops calls create more anonymous classes linearly, or is it a constant factor of code size. |
Experiment results. Control: using the current system, anonymous classes. The main point of comparison is the code generated for $ ls *study2*class
'study2$$anon$1.class' 'study2$$anon$3.class' 'study2$$anon$5.class' 'study2$.class'
'study2$$anon$2.class' 'study2$$anon$4.class' 'study2$$anon$6.class' study2.class
$ javap -c $(ls *study2*class) | wc -l
251 We see that six anonymous classes were generated. Three of these were Here are the corresponding results for using the named class $ ls *study2*class
'study2$$anon$1.class' 'study2$$anon$2.class' 'study2$$anon$3.class' 'study2$.class' study2.class
$ javap -c $(ls *study2*class) | wc -l
137 We can see that using the named class only 3 anonymous classes were created (again, the Comparing the total lines of byte code from This probably is not the most precise possible comparison, but the overall picture is pretty clear that doing this has a huge impact on the anonymous classes and corresponding byte code generated. Based on this experiment I feel pretty confident that this can be done basically everywhere. It's a bit annoying but the benefits appear to be massive. |
cc @cquiroz |
Thank you very much for doing the experiment! Cool, good to see this lines up with our intuition and most importantly that your fix works! |
Cool, this is looking great, thanks a lot |
Applying this same measurement to $ ls -1 QuantitySuite*.class | wc -l
350
$ javap -c QuantitySuite*.class | wc -l
12649 I should be able to track the improvement from adding named classes across coulomb or "all anonymous classes in the unit testing" $ ls -l *anon*.class | wc -l
420
$ javap -c *anon*.class | wc -l
15158 "all class files in testing" $ ls -l *.class | wc -l
427
$ javap -c *.class | wc -l
16012 |
That's quite a difference |
eb68883
to
93664da
Compare
@armanbilge While I've been doing this, I noticed something interesting. The various typeclasses that are subclasses of It got me thinking about the operator classes, take abstract class Add[VL, UL, VR, UR]:
type VO
type UO
def apply(ql: Quantity[VL, UL], qr: Quantity[VR, UR]): Quantity[VO, UO] This is very close to being a function: abstract class Add[VL, UL, VR, UR] extends (Quantity[VL, UL], qr: Quantity[VR, UR]) => Quantity[VO, UO] Except that the types It's not a big deal if it can't work, but if it could, it might allow more elegant definitions. |
Ah yes, you've discovered the magic of single-abstract-methods (SAMs) and
|
I think I cleared up one issue that was confusing me - the "SAM/lambda" trick will work with When I define my own named classes, I can avoid anonymous class generation regardless. |
f485d2b
to
e93247d
Compare
@erikerlandson I couldn't quite follow your last comment ... does that mean you found a workaround, to avoid generating anonymous classes without having to name them? |
@armanbilge for any of my For |
Ah, thanks for the clarification. Makes sense about given-not-inline. Interesting observation about |
when using |
Yeah, I wonder if there's some underlying compiler issue there. Scala 2 has some bugs that prevent SAMs in some situations where otherwise they could be ok. |
possibly it's a "bug" in the sense that it could avoid the anonymous generation but it doesn't. Regardless, it's been a useful exercise. Most of my operator classes require a named class but I've been able to simplify it considerably from my first attempt. |
Before (anonymous classes)
After (using all named classes)
Near as I can tell, coulomb is now introducing NO anonymous classes into the compiled code. |
This is great, it is especially useful for scala.js |
a followup to #264, alternative to reducing inlined coad bloat