Shared publicly  - 
 
In this video, +Colt McAnlis​​ gives a refreshingly candid take on the enum "problem". Almost everything about this video is fantastic. Almost. Watch it before reading more, because it does a great job of outlining the pros and cons of enum usage: https://youtu.be/Hzs6OBcvNQE

Ok. So what's wrong here?

In the middle of the video an absolutely ridiculous and sensational number is dropped whose sole purpose is to create a shock-statistic which leads to an incorrect perception of an enum's effect: 2556 bytes.

What app, in the entire history of apps written for Android, has ever had a dex size of 2556 bytes? Zero. Not one. Ever.

The video goes on to show that adding an enum bloats this fictitious app to a whopping 4188 bytes. Why that's basically 2x. I added a single enum and my app doubled in size!

Open Android Studio, go to File > New Project, select a minSdk of 16, select a 'Blank Activity' template, and click Finish. On a clean compile, how large is the dex file of this completely empty app? Two million, five-hundred and sixteen thousand, five-hundred and eighty-two bytes. That's 2,512,582 bytes. 1000x times larger than the "base" example used in the video.

Of course, this size stems from the default dependency of the extremely-useful AppCompat which in turn depends on the also useful fat cow support-v4. If you remove these two dependencies, what does our dex size become? The answer may surprise you: who cares? It's an empty app.

Even if this library-free app perfectly matches up to 2556 bytes as mentioned in the video then adding an enum is completely justified as it would be the only thing in the app.

Whatever random SHA of Square Cash I have sitting on my machine currently clocks in at 6.4MB of dex. How much of that is from enums? Maybe it's 0.01MB. Or maybe it's 0.001MB.

Like I said, this video presents the pros and cons of using enums accurately and does show the relative size difference which is what is important. It is a good video. But, the overall dex size comparison is needless and serves only to mislead you to believe the impact is greater than it really is which just destroys all that credibility it built.

As a library developer, I recognize these small optimizations that should be done as we want to have as little impact on the consuming app's size, memory, and performance as possible. But it's important to realize that throwing away an Iterator allocation vs. an indexed loop, using a HashMap vs. a binary-searched collection like SparseArray, and putting an enum in your public API vs. integer values where appropriate is perfectly fine. Knowing the difference to make informed decisions is what's important and the video nearly nails that except for this one stupid stat.
226
56
Wouter van Oortmerssen's profile photoPavlos-Petros Tournaris's profile photoSaad Farooq's profile photoGaurav Sharma's profile photo
56 comments
 
Before the type annotations were introduced, I was totally pro-enum (I like my type safety). Correctness almost always trumps performance. Now, though, it's possible to get the extra performance (in the form of memory footprint) with minimal loss of type safety. I also agree with his point that one enum is not a huge deal in the same way that a single reflection call isn't terrible, but when you rely on them everywhere, the cumulative effect can be noticeable.
 
+Josh Brown​ True. I also think the fact that enums are full classes is undersold a lot. They're a fantastic was to treat code as data in the form of implementing methods on the enums, perhaps even from interfaces, which can be passed around.
 
I'm sure we all read this:
https://medium.com/google-developers/developing-for-android-ii-bb9a51f8c8b9 and esp the Avoid Enums section.

Premature optimisation is of course bad.

But unless you are targeting recent Nexus devices and high end Samsung devices, some of use (raising my hand) are trying to squeeze every bit of performance out of devices like the Moto E, Moto G (1st and 2nd gen) etc. b/c a large percentage of our users will run this.

Material design effects, high elevation drop shadows with card views, loading Google Maps etc. already run slow enough on these cheap devices.  I'd prefer to avoid enums, and ensure that I'm doing my part to ensure my delightful UI effects run fast and true on these very low end devices.  It is a UI app after all.

I have to admit, I use GreenRobot's EventBus instead of Otto based on their performance benchmarks.

Of course I love Jake's and Square's stuff too (what Droid dev doesn't?)
 
+Jake Wharton agreed iff you're actually using the 'objectness' of enums. But if they can be replaced by an int, then they should be. They're great for the strategy pattern.
Jake Wharton
+
19
20
19
 
+Stephen Lum​ If you truly cared about performance you wouldn't use an event bus based on reflection or a ton of generated code. There's a great irony in your comment in that by using GreenRobot's new event bus you are bloating your Dex with a ton of generated classes and instances just like and enum.

This post is not a debate on using enums or not. I don't care whether you use them or not. The video does a great job of the pros and cons, like I said. The point is that the stupid scare tactic to create a false shock-statistic kills credibility.
 
+Jake Wharton agreed we are getting off topic.  By your logic, you could have said if I truly cared about performance I should be pushing as much down into the NDK as possible.

I certainly believe you don't care whether I use enums or not.

The only point I was making is that it's sanctioned via the medium post and it's trivial to avoid (as opposed to rolling my own extensively tested, battle proven, non reflective event bus across the plethora of android devices + firmware.
 
My question regarding enums and the video is this : does that size increase happen for all enums or do the 2nd and 3rd enums have less overhead?
I like the type safety of enums, but I really like that if you add to an enum and forget to add the case in a switch you'll get a warning (if you've enabled the check, which I did) 
 
Heh, I was going to mention the NDK to reply to +Josh Brown​'s comment! Blanket statements are never (ha!) the right thing and enums are no exception. Your app has hundreds of more impactful and more important optimizations to be made before you get anywhere near needing to replace enums. The platform is a completely different story than an app as well and its rules to not blindly apply to apps.

I'm advocating for the education like this video presents but with real-world examples of numbers.

+Mike Wallace​ every enum has the fixed cost as each is a full class.
 
Because it trades code size for speed, the reverse of the trade-offs being made by enums. I wrote a code-generated Otto 2.5 years ago and we determined it wasn't worth said trade-off.
 
The alternative is registering callbacks directly with the class from which you care about updates.
 
LocalBroadcastManager also works for things that truly need to be broadcasted. There's a little bit of extra boilerplate, but IMO that keeps it from being overused (where callbacks would be more appropriate).
 
continuing offtopic Registering callbacks from an IntentService where you make a network call, seem a bit awkward to me. I'd rather use an EventBus and wait to give me the result when it's done...i want to find a more effective alternative in such a specific use case but struggle to understand where RxJava can replace this specific process. Sorry for the offtopic, if anyone knows please let me know in order to create a new post for it.
 
If we really cared about performance, we'd remove 80% of the synchronized keywords from the SDK. The enums, in comparison, have very little performance impact and much greater value.
 
+Jake Wharton I wrote a code generated event library for Android. Do you have some more information to share about your decision with yours (sorry for hijacking the thread)?
 
OK, so if I understand your argument: your point is that once all that other crap is turned on, Enums only account for a small % of the final size; and that I was just showing base numbers for shock value. So, shame on me.

Which is a fine statement to make. I'd jus like to point a few things out (this is long, please bear with me):

Firstly - thanks for watching the video and thinking I'm a dumb-ass. This is good feedback; and generally, my manager agrees with you (+Reto Meier  is actually president of the Colt is a dumb-ass club).

Secondly - Just to be clear, this isn't a fake app. It's quite easy to produce something within a stones throw: In fact I just reproduced the results on my laptop here. With JDK8, SDK 21, and no AppCompat, I can get a blank DEBUG DEX at 3948 bytes. (FWIW the signed, release build with some pro-guard settings gave us the .DEX of 2556 bytes, trying to be as minimal as possible.)
And just to make sure I wasn't drunk (again) when taking those numbers, I added the same code-snippets from the video.
Int-version : 4140 bytes (+192 bytes)
Enum-version : 5500 bytes (+1552 bytes)

(Which is good, cause I was worried when I read your post that I fucked up on the data.) phew

Thirdly : Your point is that "REAL applications will never be that small and enums are only a small % of them".

Sure, that's fine. But let me ask you a counter question : How does one go about finding the exact impact a single enum has on your DEX file, in bytes?

You can't really find this number with a "file->new" application, because there's too much boilerplate and settings going on. You also can't do this on your existing 1-million line codebase. In these situations the numbers would always be fudged / variable, because of code-removal / data scraping/ compiler optimizations (etc etc.).

To find the exact impact, I had to remove EVERYTHING from the app so those things weren't influencing the final result, and I could stand on camera, and say "this is the true number." 

So yes, you're correct: real apps aren't that small. BUT  now we have a quantifiable metric : Enums seem to add about 1.4k-1.5k in DEX size, per declaration.
That's a great number, because now, a real engineer, who's struggling with DEX sizes can say "Shit!  That library we're linking has 100 enum decls! that's like 136k of size we're just wasting!"

That's real data that folks can use, and we had to turn off everything else to get it. I can understand what that seems weird to you; But my goal was to give data that was un-influenced by the other information. This wasn't something subversive, It's just that my intent was different than perhaps what you were expecting.

Finally - Can I just make, one, small request for the folks reading this thread? Please stop thinking of things like Enums/ArrayMaps/Iterator fixes as Premature Optimizations. That's really the wrong mentality.

Think of it this way. You KNOW that you're going to eat food, and it's going to decay your teeth. So, each day, you brush them so that you prevent these problems. It's a preventative measure, because you know that if you don't, the pain of pulling a tooth later really sucks. So, you slog through the process of brushing your teeth every day, to avoid that huge pending problem.

Same thing goes for your code. This is "Preventative Optimizations" It's doing the little things, day in-and day-out to make sure that you won't have to pull a (metaphorical) tooth later. 

Memory is a scarce resource on Android; it will run out. that's a hard truth that we've been trying to slowly reveal to developers over the past 6 months.

So yes, PLEASE : optimize for your bitmap sizes; Reduce allocation churn; re-use bitmap space; Pick a smaller serialization format; use WebP; all the big stuff you should be doing.

But don't neglect the small stuff. The small preventative work that you do in your code to save memory, is saving you big in the long run.

It's not premature. It's preventative. 
 
In fairness, the main reason I formed the "Colt is a dumb-ass" club is when I discovered you spend your leisure time engaging in martial arts in which being choked is an apparently legitimate move.

In terms of Android performance you're usually spot on. You make a legit point about enums. 
 
+Colt McAnlis thanks for the detailed response! Just to be clear, I'm neither advocating for enums nor advocating against integers with this post. I stand firmly in the measure, analyze, improve camp for all optimizations. Our app is filled with a mix of enums and ints, hash maps and array maps / sparse arrays, and for-each loops and indexed for loops where appropriate.

My only criticism was the use of 2556 bytes number which, when integers were introduced, was badged with a delta of 124 bytes (or whatever) but when enums were used the total bytes was updated to 4118. This makes you feel like the enum delta is larger than it actually is. I have no critique on the points made and as I said multiple times, I thought it was a great video–the best aggregation to date of the actual pros and cons of this choice. But the presentation of these numbers–the choice of overly-small base dex size and the differing presentations of the effect of int vs. enum–was my problem. These are classic techniques to make one option appear worse than the other while the actual difference is not as great. In real-world dex size numbers, the total change would have felt less impactful.
 
+Jake Wharton I think that's a fine comment about the numbers. Again, that wasn't intentionally subversive; IIRC we came to that order to avoid the viewer having to do the head math real-time. I'll make sure next time around that we keep comparing apples-to-apples.
 
+Reto Meier Goddamnit! The point is to AVOID being choked out. Sure, I'm.. generally bad at avoiding that... so... i suppose... i see your point.. 
 
+Jake Wharton

"Your app has hundreds of more impactful and more important optimizations to be made before you get anywhere near needing to replace enums. The platform is a completely different story than an app as well and its rules to not blindly apply to apps."

Sure sure sure! I wasn't advocating ripping out enums as the source of all evil and the major bottleneck when performance tuning. Colt's toothbrush analogy said it best, and I said that it was trivial for me to use primitive int's instead of enums when I need an enum like structure.

OK, I've got a blanket statement that hopefully we can agree is universally true.  Education and continual learning with meaningful discussion is a good thing :-)

Peace
 
+Pavlos-Petros Tournaris 

continuingofftopic I'm using an EventBus for pretty much the identical scenario e.g. having an IntentService publish events.

As Jake mentioned if you don't like what GreenRobot's event bus is doing and prefer to be on Jake's side of that tradeoff, you can use Otto. When I went the event bus route, I liked both Otto and EventBus when I evaluated and chose EventBus based on this:
https://github.com/greenrobot/EventBus/blob/master/COMPARISON.md

Performance and event delivery on a background thread were the keys for me.

As an alternative, you could use a DetachableResultReceiver which is what I did in the early days.  It's been awhile, but I believe its in iosched 2011...I believe it's used early on in MainActivity so not too hard to find.

HTH
 
I prefer GreenRobot's EventBus than Otto. Tried it on the past but wasn't satisfied. My point is, is there any other kind of development that solves this specific case or should I stick with EventBus ?
 
Does anyone else feel that, with the wisdom of hindsight, the Java language was maybe not a good fit for Android? I mean, "don't use enums", "don't use enhanced for loops"... Don't use Java? 
 
What's the big deal here? Just watched the video and to me it's just a matter of showing how much a single enum declaration adds. Not about giving shock figures of an app doubling in size. To me the message came out pretty clear tbh.
 
Thanks for this open minded discussion - and the initial video too! :-) Now we know about the net impact of the enum and thats one important cornerstone of many of cause. One may waste lots of resources by choosing many cool tools using reflection etc. And not realizing the zillions of classes being added and CPU cycles wasted. Fun thing is that a thoughtful rewrite of any perfect APP would typically lead to an even more perfect APP. Doing this in 2k steps or 500k at once. Thanks again and beer for us all :-)
 
So... The examples I have seen that talk about Enums being BAD for whatever reason, only use enums in their basic way.. What about where java enums are more useful, when you link the enum value to more information.. eg on https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html you have the planet enum.. (BTW I use enums like this in my apps to declare static configuration).

public enum Planet {
    MERCURY (3.303e+23, 2.4397e6),
    VENUS   (4.869e+24, 6.0518e6),
    EARTH   (5.976e+24, 6.37814e6),
    MARS    (6.421e+23, 3.3972e6),
    JUPITER (1.9e+27,   7.1492e7),
    SATURN  (5.688e+26, 6.0268e7),
    URANUS  (8.686e+25, 2.5559e7),
    NEPTUNE (1.024e+26, 2.4746e7);

    private final double mass;   // in kilograms
    private final double radius; // in meters
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }
    private double mass() { return mass; }
    private double radius() { return radius; }

    // universal gravitational constant  (m3 kg-1 s-2)
    public static final double G = 6.67300E-11;

    double surfaceGravity() {
        return G * mass / (radius * radius);
    }
    double surfaceWeight(double otherMass) {
        return otherMass * surfaceGravity();
    }
    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("Usage: java Planet <earth_weight>");
            System.exit(-1);
        }
        double earthWeight = Double.parseDouble(args[0]);
        double mass = earthWeight/EARTH.surfaceGravity();
        for (Planet p : Planet.values())
           System.out.printf("Your weight on %s is %f%n",
                             p, p.surfaceWeight(mass));
    }
}
 
Needless to say that the base app in the video has a ListView, AppCompat, NavigationView and FAB from design library. :)
 
Has been parsing JSON using Gson into Object Models and Enums...
Will starts using static final int (so old school @@, I migrated from static final int to Enum when it was J2SE 1.5.0) with annotations afterwards.
 
+Mathew Winters In that scenario, you're still paying all the overhead of the enum, which is going to be significantly larger than just a class method to do the same thing. That's the problem i find with ENUMS; their usefulness often hides the actual performance burden they carry with them.
 
+Colt McAnlis Moving to FlatBuffers would be kind of huge transition for already JSON oriented apps. Would there be any video dedicated on Flatbuffers, or any kind of a tutorial on how does an indie developer makes such a transition ? 
 
+Colt McAnlis Sadly I have no control on server side. (they use same APIs for Smart TV which cannot run FlatBuffers)
 
+Pavlos-Petros Tournaris What I mean is the APIs...JSON is still alive because some front-end apps (e.g. SmartTV app, JS Win8 app) are in Javascript.
 
I agree fully.

Using ints because they take smaller space is ridiculous. The many benefits of enums are worth those bits any day.
 
+Pavlos-Petros Tournaris There is currently no automated way to deduce a schema from sample JSON, you'll have to write one by hand. Though such automated schema creation certainly could be made.
 
Great points brought up all around. To +Jake Wharton's  point, while watching the video, I thought +Colt McAnlis was talking about some super secret portion of the app that's loaded into the system's main memory and the rest of the app is in RAM or something. And I think that was mainly because of that number chosen for size. Consequently, I totally bought the enum argument. I might have realized on my own at some point that I was mistaken but that video definitely started me off wrong.
And to +Colt McAnlis's point about 'premature optimization', I feel like it's one of the those overused buzz words. Every pattern we use in our apps was a premature optimization at some point. Premature optimizations are only those you can't include in your workflow, the rest are patterns. Otherwise, we shouldn't be using ViewHolders with our ListViews. Why optimize for recycling until you know that's a problem for your app ?
 
Hi +Jake Wharton i have lots of string constant in my project shall i keep all of them as static in single class or they should be bound to singleton object and divided into multiple small classes.

Add a comment...