15

There are many questions and answers about using public fields in Object Oriented Programming, and most of them recommend not to use public fields for many reasons.

But when I looked into Android's code I found some classes are using public fields. For example Android.view.View has public fields mCachingFailed and mAttributes.

Why are they public? It is hard to think this is a mistake on Google and AOSP's part.

dimo414
  • 47,227
  • 18
  • 148
  • 244
Joon Hong
  • 1,337
  • 15
  • 23
  • Why are you asking us? Ask the authors. They know. – user207421 Nov 23 '15 at 03:29
  • 3
    @EJP They said they did it intentionally in Android issue tracker.(they used public + `@hide` instead of private) I have no personal contact to Android developers, and I think Android issue tracker is not for Q&A. – Joon Hong Nov 23 '15 at 23:39
  • Most likely for performance reasons, i.e. classes from other packages need to access them on some critical path. Indeed `android.widget.ListView` references it in `drawChild(Canvas canvas, View child, long drawingTime)`. But without any comment from authoritative figures this is just a conjecture. – Kai Nov 25 '15 at 03:52

2 Answers2

16

It isn't inherently a mistake to have public fields. It is not, as the bounty note suggests, an "OOP-fundamental-violation". After all these two classes are (for most purposes) identical:

public class DemoA {
  public int field;
}

public class DemoB {
  private int field;

  public int getField() { return field; }
  public void setField(int value) { field = value; }
}

That is to say, if you intend for callers to have direct read and write access to a field adding a getter and setter may just be extra boiler-plate.

The benefit of getters and setters, even if they do no other work than reading and writing to fields, is that they abstract the fact that the data is stored in a field at all. It could be stored in an external data source, or computed on the fly, or whatever you'd like, and callers don't have to worry about how the behavior is implemented. This is definitely a good practice in general because it separates the callers concerns (the API) from your concerns (the implementation).

However sometimes it's just overkill, and it's perfectly reasonable to expose public fields if that's the best way to provide the behavior your callers need. Most often, this is done for value types, classes that exist solely to group a number of fields together. There's little benefit to writing out scores of getters and setters when everything you need a class to do can be accomplished by simply making the fields public.

As a practical matter, Android has an additional concern. Method calls are expensive and the number of methods an app can (easily) define is limited to ~65k. For cases where it's safe to do so, exposing a field directly reduces the method overhead by two and saves valuable CPU time. That might not seem like a lot, but it adds up quickly.

dimo414
  • 47,227
  • 18
  • 148
  • 244
  • In addition I once stumbled over an article (but cannot find anymore) about access to a field directly is (slightly) faster than by getters and setters (on some architectures). This would only be measurable in high performance applications. I don't know, but maybe the public fields were implemented in some classes for this reason. For example the View class fields might be accessed often (and preferably as fast as possible). I don't know if this is still correct, but I still wanted to note. – mad_manny Nov 25 '15 at 06:53
  • Sure, it's potentially marginally faster. But both the compiler and the JIT could potentially optimize getters/setters to actually be field accesses, so it's likely a very limited overhead. More to the point though, you should avoid making design decisions for efficiency reasons until you're certain it's a bottleneck. The cost of writing bad code in the name of efficiency is much higher than the cost of slight inefficiencies that good patterns sometimes come with. – dimo414 Nov 25 '15 at 06:58
  • @mad_manny I think this is what you read: http://developer.android.com/training/articles/perf-tips.html#GettersSetters "It's reasonable to follow common object-oriented programming practices and have getters and setters in the public interface, but within a class you should always access fields directly." – Joon Hong Nov 25 '15 at 07:50
  • 2
    @Joon Hong: No, this was not the one. The one I read was an empiric one. Anyway, I follow dimo414 in the point, that "you should avoid making design decisions for efficiency reasons " – mad_manny Nov 25 '15 at 08:17
6

Check out this section from developer.android.com:

In native languages like C++ it's common practice to use getters (i = getCount()) instead of accessing the field directly (i = mCount). This is an excellent habit for C++ and is often practiced in other object oriented languages like C# and Java, because the compiler can usually inline the access, and if you need to restrict or debug field access you can add the code at any time.

However, this is a bad idea on Android. Virtual method calls are expensive, much more so than instance field lookups. It's reasonable to follow common object-oriented programming practices and have getters and setters in the public interface, but within a class you should always access fields directly.

Without a JIT, direct field access is about 3x faster than invoking a trivial getter. With the JIT (where direct field access is as cheap as accessing a local), direct field access is about 7x faster than invoking a trivial getter.

Note that if you're using ProGuard, you can have the best of both worlds because ProGuard can inline accessors for you

http://developer.android.com/training/articles/perf-tips.html#GettersSetters

Most likely, this is the reason you see public fields in AOSP.

Jared Rummler
  • 37,824
  • 19
  • 133
  • 148
  • It's great to know that it was mentioned in the official Android developer website. However, we have to note that the webpage is about avoiding "internal" getters/setters, and not mentioning anything about the validity of having a public field to be accessed directly from outside the class. (See also: http://stackoverflow.com/questions/6716442/android-performance-avoid-internal-getters-setters) – Taka Jul 06 '16 at 02:25