Archive for category Java

Return of the Statically Typed Languages

My good buddy Steve Yegge posted quite an article yesterday. It’s the transcript of a presentation he gave at Stanford a few days ago, and the overall idea is that dynamically typed languages are on the rise and statically typed languages are on their way out.

I highly recommend reading the entire transcript, it’s very entertaining and, like a lot of the stuff that Steve writes, filled with insight and provocative thoughts. Unfortunately, this time, just like a supervillain, Steve put his fantastic observation skills and remarkable breadth of knowledge to serve a lost cause. There’s no easy way to put it, Steve, but you’re just wrong :-)

I sent him a reaction email shortly after he posted his article, and he encouraged me to make it public in an attempt to document our two opposing viewpoint publicly. I’m happy to be the Luke Skywalker to his Darth Vader.

Evil shall not prevail.

Scala

First of all, I was initially very excited about Scala until I realized that two features were close to being deal breakers for me: implicits and pattern matching.

Have you taken a look at implicits? Seriously? Just when I thought we were not just done realizing that global variables are bad, but we have actually come up with better ways to leverage the concept with DI frameworks such as Guice, Scala knocks the wind out of us with implicits and all our hardly earned knowledge about side effects is going down the drain again.

As for pattern matching, it makes me feel as if all the careful data abstraction that I have built inside my objects in order to isolate them from the unforgiving world are, again, thrown out of the window because I am now forced to write deconstructors to expose all this state just so my classes can be put in a statement that doesn’t even have the courtesy to dress up as something that doesn’t smell like a switch/case…

About the difficulty to impose a non-mainstream language in the industry

this in the beginning: this is 80% politics and 20% technology, right? You know.

I find this very disingenuous. Steve, you know it’s not true, right? Most of the people around you would love to be able to use the language that they really like, but the cost for the company just doesn’t make sense. I would therefore revise your break down as follows: the reason for not using a non-mainstream language in a big company is 10% politics 10% technology and 80% common sense.

Let me turn the table on you and imagine that one of your coworkers comes to you and tells you that he really wants to implement his part of the project in this awesome language called Draco. How would you react?

Well, you’re a pragmatic kind of guy and even though the idea seems wacky, I’m sure you would start by doing some homework (which would show you that Draco was an awesome language used back in the days on the Amiga). Reading up on Draco, you realize that it’s indeed a very cool language that has some features that are a good match for the problem at hand. But even as you realize this, you already know what you need to tell that guy, right? Probably something like “You’re out of your mind, go back to Eclipse and get cranking”. And suddenly, you’ve become *that* guy. Just because you showed some common sense.

Tools

Not harder to build dynamic tools than for static languages, just different.

I still strongly disagree with that. It is different *and* harder (and in some cases, impossible). Your point regarding the fact that static refactoring doesn’t cover 100% of the cases is well taken, but it’s 1) darn close to 100% and 2) getting closer to it much faster than any dynamic tool ever could. By the way, Java refactorings correcting comments, XML and property files are getting pretty common these days, but good luck trying to perform a reliable method renaming in 100 Ruby files.

Generics

I no longer bother trying to understand why complex Generic examples are so… well, darn complex. Yes, it’s pretty darn hard to follow sometimes, but here are a few points for you to ponder:

  • 90% of the Java programmers (including myself) only ever use Generics for Collections.
  • These same programmers never go as far as nesting two Generic declarations.
  • For API developers and users alike, Generics are a huge progress.
  • Scala still requires you to understand covariance and contravariance (but with different rules. People seem to say that Scala’s rules are simpler, I’m not so sure, but not interested in finding out for the aforementioned reasons).

Performance

I’m actually surprised you spend so much time defending the performance of dynamic languages, because I don’t think it’s worth it. Yeah, they’re slower overall but in the same margin as Java used to be slower than C++, and we know how that turned out. Not much to argue about here in my opinion.

What will keep preventing dynamically typed languages from displacing statically typed ones in large scale software is not performance, it’s the simple fact that it’s impossible to make sense of a giant ball of typeless source files, which causes automatic refactorings to be unreliable, hence hardly applicable, which in turn makes developers scared of refactoring. And it’s all downhill from there. Hello bit rot.

I hate giving anecdotal evidence to support my points, but that won’t stop me from telling a short story that happened to me just two weeks ago: I found myself in this very predicament when trying to improve a Ruby program that 1) I just wrote a few days before and 2) is 200 lines long. I was staring at an object, trying to remember what it does, failing, searching manually in emacs where it was declared, found it as a “Hash”, and then realized I still had no idea what the darn thing is. You see my point…

Javascript

Javascript is on the verge of becoming part of the assembly language family, and toolkits like GWT are making sure that this will happen before too many developers join the pool of low level language victims. I’m sure you can relate to that stigma.

Also, I think you are vastly overestimating how the optimization work on Javascript is going to advance the science in that area. I’m sure thousands of very smart researches are busy doing that right at this moment, but come on: Javascript has become very much good enough for a lot of apps.

And what’s interesting is that, as opposed to Java, Javascript has an upper bound where it no longer matters to make things go faster, because there is only so much you want to do on the client anyway. Gears is even showing us that we can do a decent amount of processing on the client, but so few applications need that that I think the backdoor tricks that GWT uses (such as image bundles) are much more clever and much more useful than any of the stuff that you show in these slides.

Emacs

You know, even Emacs has to evolve.

No: it’s Emacs users who have to evolve.

Error messages

And the weird thing is, I realized early in my career that I would actually rather have a runtime error than a compile error.

You probably already know this, but you drew the wrong conclusion. You didn’t want a runtime error, you wanted a clear error. One that doesn’t lie to you, like CFront (and a lot of C++ compilers even today, I hear) used to spit in our faces. And once I have a clear error message, I much prefer to have it as early as possible, thank you very much.

Trace trees

The PDF link is broken.

The dynamic nuclear winter

And everybody else went and chased static. And they’ve been doing it like crazy. And they’ve, in my opinion, reached the theoretical bounds of what they can deliver, and it has FAILED.

Quite honestly, words fail me here.

Flamewar

Finally, the largest flamewar that I ever witnessed involving Stallman was when he dissed XEmacs on comp.lang.emacs and it quickly turned out in the discussion he hadn’t even launched the darn thing. Get your history facts straight!

Conclusion

Interestingly, I am currently working on a brand new presentation on this very topic that I’ll be making at Jazoon next month. I’m still working out the details, but this presentation will take a quick tour of the dynamic landscape, contrast it with Java and argue that statically typed languages in general and Java in particular have never been in a stronger position to remain the language of choice for large scale software for the decade to come.

Hope to see some of you there!

Breaking free from the tyranny of languages

I recently came across this documentation page from the .Net API.

I was investigating the possibility of creating a Map that would allow String keys to be case insensitive in Java. Neither the language nor the standard libraries allow you to do this easily at this moment, because 1) hashCode and equals are methods that are defined on Object and 2) all the collection classes use these methods directly. Therefore, I was wondering how hard it would be to extract these two methods in an external class (you could use a Trait in Scala) and delegate these calls there instead of on the objects themselves.

This idea is not exactly new and it would be pretty easy to implement, and as you can see from this page, it is already supported in .Net.

But that’s not what caught my eye.

Do you notice anything special on this page? Look again.

The key here is to realize that this is not a “C# page” or a “Visual Basic page”. It’s “.Net documentation page”. And for this reason, it describes the functionality in general terms and then it gives specific examples in not one but five languages.

Maybe I’m easily impressed, but I find this amazing.

Here is the deal: I have always been a fan of COM. Since day one. Well, not exactly day one since the early days of COM in C and C++ were extremely painful, but I certainly saluted the ambition behind the idea: trying to make all Windows applications 1) accessible from the outside and 2) from any language. Until Microsoft created COM, this goal had never really been achieved by any technology.

Fast forward thirteen years: COM has morphed into .Net, the complex COM binary interface is now hidden behind a neat virtual machine with a powerful bytecode set, and the dream of writing applications independently of languages is a reality on the Windows platform. Hats off to Microsoft.

Now, where does that leave us, Java developers?

Well, we have achieved an independence of sorts, although it happened much more by accident.

Microsoft built its framework with a clear vision that was spelled out around 1995 and that took many years to carry out. Java, on the other hand, started with a clear focus on the language, with the JVM and the bytecode as a simple foundation to make it easier to run Java programs on several platforms (actually, event the intent for the JVM has changed over the years: it was first designed to run on embedded devices, then in web browsers as applets, and it finally found its true vocation on the server, something that Sun never saw coming).

What’s interesting in this story is that not only did Java emerge as a superstar of languages, but it slowly and surely dragged the JVM and its bytecode into the spotlight as well. The versatility of the original design should certainly be saluted, but it’s eventually the formidable Java ecosystem and its users that took the JVM to heights never envisioned.

It started innocently with a few experiments that generated bytecodes to alter existing classes or to create new ones on the fly, and it’s now culminating with not only some of the most innovative frameworks I’ve seen in years, but the JVM has also the foundation for a multitude of new languages that not only run JVM bytecodes but that also interoperate seamlessly with the Java platform.

In a way, Java has enabled language independence as well. It’s not as extensive as .Net, but it certainly runs on many more platforms.

First steps with GWT

I recently spent some time porting a SWT application to GWT, and it’s been a real pleasure. Ever since I heard about GWT, I have been very eager to put my hands on it and try it for real. Pity it took so long.

First of all, why all this interest on my part? It’s simple really, and I can summarize it in one sentence: I love the idea behind AJAX and dynamic web pages but I don’t like Javascript.

Don’t get me wrong: I know it’s a great language and I’ve always had good success and rewarding results whenever I have taken the time to write a few lines of code to solve a few minor problems on my web sites, but the perspective of writing entire applications in this language has been a very big turn off for me, so I’ve been avoiding it. Anyway, I’m not going to go into details since it’s not the topic of this post. Let’s get back to GWT.

Ever since AJAX became popular, I have waited for the second generation to emerge. By “second generation”, I mean whatever tools or languages that would save me the trouble of having to 1) program in Javascript and 2) deal with browser compatibility hell. In other words, to me, Javascript and XmlHttpRequest is assembly language, and I draw a lot more satisfaction writing code at a higher level.

Enters GWT, which promises to let me use my favorite development tools (Java and Eclipse) to the fullest (well, almost) while leveraging AJAX without any restrictions. Sign me up!

In the coming days, I’m planning on posting in more details about my experience with GWT, both philosophically and technically. GWT has been out for quite a while now, and there are plenty of tutorials, books and articles describing all its features, so in an attempt not to repeat all of this material, I’ll try to stick to a few original details and tidbits that I came across.

Test method priorities in TestNG

A TestNG user recently requested an interesting feature: method priorities.

The idea is to be able to assign a priority to a test method (or an entire class) to guarantee that it will be run before other methods with a higher priority. Note that this is slightly different from dependent methods, since it’s just about ordering: if a method with a priority 2 fails, methods with higher priorities will still be run.

As it turns out, this is very easy to implement with one of TestNG 5.8 newest features: method interceptors.

TestNG lets you declare a class implementing the interface IMethodInterceptor, whose signature is:

public interface IMethodInterceptor extends ITestNGListener {
  List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context);
}

TestNG passes the list of methods it’s about to run so you get a chance to reorder them. Implementing method priorities with this interface is very simple.

Let’s start with what we want this feature to look like. In the following example, I declare three kinds of priorities:

  • Priorities at the method level.
  • A priority at the class level.
  • No priority. When no priority is defined on a method, we want to look for a priority on the class first, and if none can be found, the priority will receive a default value of 0.

Here is our test:

@Priority(10)
public class PriorityTest {
  @Test
  public void b1() { System.out.println("Default priority");}

  @Priority(-3)
  @Test
  public void a1()  { System.out.println("Priority -3");}

  @Priority(-3)
  @Test
  public void a2()  { System.out.println("Priority -3");}

  @Priority(3)
  @Test
  public void c1()  { System.out.println("Priority 3");}

  @Priority(3)
  @Test
  public void c2()  { System.out.println("Priority 3");}

  @Priority(4)
  @Test
  public void d1()  { System.out.println("Priority 4");}
}

Next, we implement the @Priority annotation:

@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Priority {
  int value() default 0;
}

Fairly straightforward: we make the annotation valid on methods and types only, and we use the shortcut value() annotation so we can specify @Priority(1).

Now comes the implementation of the IMethodInterceptor:

public class PriorityInterceptor implements IMethodInterceptor {
  public List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context) {
    Comparator<IMethodInstance> comparator = new Comparator<IMethodInstance>() {
      private int getPriority(IMethodInstance mi) {
      int result = 0;
      Method method = mi.getMethod().getMethod();
      Priority a1 = method.getAnnotation(Priority.class);
      if (a1 != null) {
        result = a1.value();
      } else {
        Class cls = method.getDeclaringClass();
        Priority classPriority = cls.getAnnotation(Priority.class);
        if (classPriority != null) {
          result = classPriority.value();
        }
      }
      return result;
    }

    public int compare(IMethodInstance m1, IMethodInstance m2) {
      return getPriority(m1) - getPriority(m2);
    }
  };

  IMethodInstance[] array = methods.toArray(new IMethodInstance[methods.size()]);
  Arrays.sort(array, comparator);
  return Arrays.asList(array);
}

The heart of this implementation is our Comparator, which tries to find a @Priority annotation the method it receives in parameter. If it can’t find any, it looks on the declaring class, and failing to find one there as well, assigns it a default value. The intercept() method simply sorts the methods with this comparator and returns it.

Now, let’s run our test without using that interceptor:

<suite name="Example">
  <test name="Method interceptor example" >
    <classes>
      <class name="priority.PriorityTest" />
    </classes>
  </test>
</suite>

As expected, the output is fairly random:

Priority 3
Default priority
Priority 3
Priority -3
Priority -3
Priority 4

Now we declare our interceptor in the testng.xml file:

<suite name="Example">
  <listeners>
    <listener class-name="priority.PriorityInterceptor" />
  </listeners>

  <test name="Method interceptor example" >
    <classes>
      <class name="priority.PriorityTest" />
    </classes>
  </test>
</suite>

And we get the expected outcome, with our method without any @Priority receiving the class priority (10) since it didn’t define any itself:

Priority -3
Priority -3
Priority 3
Priority 3
Priority 4
Default priority

To verify that our class priority implementation works, we can remove the @Priority class annotation. In this case, our method without any @Priority should receive a priority of 0:

Priority -3
Priority -3
Default priority
Priority 3
Priority 3
Priority 4

As you can see, Method Interceptors allow you to replace TestNG’s ordering of test methods with your own. It’s particularly powerful if used in conjunction with annotations, as shown in this example, but it’s also possible to imagine other external configuration factors to customize TestNG’s running engine to your liking.

Tags:

TestNG and Scala

There’s been a lot of activity in the TestNG world lately… Here are some highlights.

TestNG in Scala

Josh Cough has been busy working with TestNG and Scala. As a credit to Scala’s great integration with the JVM, it looks like the task was rather easy and Josh is showing a few examples in this blog post.

I notice two interesting pieces. First, a Data Provider:

@DataProvider{val name="generators"}
def createGenerators = {
val gens = Array(off, on)
for( x <- gens; y <- gens ) yield Array(x,y)
}

Notice how the same array is used to generate the two dimensions of the boolean matrix... This data provider will simply return the four possible combinations of "on" and "off" pairs.

The test making use of that Data Provider is fairly straightforward:

@Test{ val dataProvider="generators" }
def testAndGateStates(genA: Generator, genB: Generator){
val and: AndGate = new AndGate(genA, genB);
val whatItShouldBe = genA.on && genB.on
assertThat( and.on, is(whatItShouldBe) );
println( and.on + "==" + genA.on + "&&" + genB.on )
}

Notice also the appearance of HamCrest (assertThat).

ScalaTest

Bill Venners, from Artima, has also been busy cranking Scala code, and he came up with this nifty test framework called ScalaTest. His 0.9 release made the rounds and the discussion on Artima is now up to 58 replies(!).

Not surprisingly, Josh chimed in on the thread about the 0.9.1 release and TestNG support in ScalaTest was achieved in less time it took to write these words (I'm a slow typist). Talk about a match in heaven!

ReportNG

On a different front, the efforts to replace the default TestNG reports have not abated. First, there were Cosmin Marginean's XSL based reports, and now we have ReportNG, by Daniel Dyer, who uses Velocity to achieve grace and aesthetics in testing reports (who would have thought?).

Surefire 2.4 release

TestNG users who use Maven to build their code have been having a very hard time these past months. Because of various incompatibilities in the ways that TestNG and Surefire have evolved, TestNG users have been forced to use Surefire snapshots, which are notoriously unstable, and all kinds of mayhems and cryptic errors ensued.

These dark days are now over: Surefire 2.4 is out and it fully supports the latest TestNG releases.

Deleting SNAPSHOT files has never felt so good.

Book review

Finally, Masood Mortazavi likes our book so much that he decided to write a review. And we didn't even have to pay him!

And that's all for today...

The myth of the Killer App

An innocent blog post on Lambda the Ultimate has generated a storm of comments about the idea of a killer app for programming languages.

I’m sure you’ve heard this expression before, and the idea is very simple: it’s an application which, in and of itself, will promote its infrastructure (the operating system, or the programming language or the framework it’s built on) from obscurity to instant fame and de facto standard overnight.

For example, one might say that Microsoft Office was Windows’ killer app. Of course, this would be simplifying the equation somewhat since a lot of factors made Windows the success it is today, but you get the idea.

While reading through these comments, I started questioning the very existence of the killer app concept. Especially for programming languages.

Let’s start with Java. Does Java have a killer app? Did Java go through the transition “obscurity -> killer app -> fame”?

Back in the early Java days (circa 1996), there was one thing that made Java stand out from other languages. It doesn’t mean that Java was more popular than these languages, nor that it was gaining momentum: it’s just that it was attached to a particular concept that was unique to it and because of that, it received a lot of hype and was discussed heavily on Usenet and other forums.

Do you remember what that killer app was?

Applets.

Thanks to applets, Java was going to take over the world and redefine the web as we know it.

We all know what happened.

Applets never went anywhere, but Java had enough interesting properties that a lot of programmers started working with it in many areas, most of them never envisioned by any pundit at the time. Who would have guessed back then that Java would become the de facto standard on the back-end, sharing an equal footing with .Net in delivering millions of transactions every day to users around the world?

Let’s take another example: PHP.

Does PHP have a killer app?

None that I can think of. Of course, a lot of very successful programs and web sites are written in PHP (forums, blogs, etc…), but none of these can be considered “clinchers”. Instead, PHP became successful quietly, discreetly, behind closed doors, while both programmers and the required infrastructures (massive support by Internet Service Providers) were being slowly achieved without anyone realizing it. To onlookers, it looked as if one day we woke up, and PHP was everywhere. But make no mistake: the process was continuous, slow and developed on a massive scale.

A similar argument can be made for Javascript.

The more I thought about it, the more I started wondering if the idea of a killer app isn’t a fallacy. Or worse: a kiss of death. As soon as a programming language or a framework finds itself in need of a killer app, it has already failed and its proponents are just reaching and trying to save a product that they know is already slowly falling back into obscurity, as the rest of the world inexorably percolates toward the next big thing, one that makes them truly more productive and that doesn’t need bigot advocates to sell.

Maybe what we are really looking for is not a killer app but killer apps. Not one defining product by which all the others are measured, but a multitude of tiny ones which, individually, don’t really deserve any particular mention, but when put together, create a comfortable ecosystem in which programmers thrive, are productive and enjoy working in.

Now, let’s see if we can find the Next Big Programming Language using this criterion…

Sun acquires MySQL AB…

Time for Sun to rename its ticker symbol to “SQL”?

I'm not tired of Java yet

Rick Hightower posted an interesting follow-up to Zed’s rant against Ruby on Rails. There are a lot of insightful comments in this discussion, and one in particular caught my attention:

People are tired of dealing with Java’s many idiosyncrasies

I’ve been reading this a lot these past years but I’ve yet to see any evidence of it.

Come to think of it, this statement is mostly coming from bloggers, but…

  • They don’t speak for all Java developers (actually, they represent a very tiny fraction of them).

  • They need to drive traffic to their blog, and nothing achieves this goal better than posts titled “Java is dying” or “Ruby has won”.

I’ve been programming in Java for more than ten years. I have studied a lot of languages, and I keep learning new ones just out of curiosity. I even use some of these exotic languages here and there as the need warrants. Yes, some of these feel really good to program in (Ruby and Groovy for example), but at the end of the day, I still like Java. A lot.

Sure, there are things in the language that bother me, but it’s true for any language, and as a whole, I always enjoy going back to my favorite Java IDE and leverage its superb features to write code that I find is elegant and that achieves a goal.

Whenever I use a non-Java language, I always have this nagging feeling in the back of my head that something is going to hold this piece of code from ever becoming mainstream or used by a lot of people. It can be because the language is slow, or that it needs an interpreter. Or that it will be hard to deploy my program on a user’s machine. Or that this language was created before OO became mainstream and its support for new paradigms feels retrofitted and creaky.

Or that its support for floating point is very poor. Or that its thread API is primitive and the author of the language keeps saying that it’s no big deal and that you can do without that. Or maybe it doesn’t have any Web framework that supports internationalization, a clean MVC model or out-of-the-box testing. Or I want to write a client application that leverages its host operating system but all that it offers is an ugly-looking user interface and leaking metaphors.

None of these defects take away the pleasure I derive from sometimes straying off the beaten path and writing code in an exotic language, but it does set my mind into a mode that tells me that this piece of code will never be promoted past the “toy” status.

Toy listings are great for sniped blog entries, but a mainstream programming language they do not make.

Whatever your favorite language is, be it Scala, Ruby, Python or Groovy, I’m with you. I really am. I understand the warm glow you feel when you write code in your language because I feel it too. But what you need to understand is that there is very little chance that your language will displace Java in any way in at least the next five years to come.

But please, keep posting cute code snippets that show how great your language is, because I love to be challenged in the way I think and indirectly, Java benefits from all these great ideas that keep being posted in the blogosphere.

It's okay to return null

This blog post called Returning None is evil caught my attention. In this article, the author (Marty Alchin) tries to explain why you should never return None (this is Python’s equivalent of None). Since he also takes this opportunity to take a few unnecessary potshots at Java, I thought I’d make a few comments.

Marty seems to be prone to exaggeration. For example, he states that NullPointerExceptions (or rather, their Python equivalent) are:

exceptionally hard to debug

It typically takes me less than a minute to find such errors. The first ten seconds are dedicated to jumping to the place where the exception occurred, and the remaining to finding where that value came from (usually instantaneous with Java IDE’s. Python doesn’t have those… pity).

Marty then continues by saying that returning a None value indicates that

an error occurred

Well, not always. For example, when you look up a key that doesn’t exist in a dictionary, is this an error? It seems very much part of the contract of the class to me. There are many, many other situations where the fact that a value cannot be returned is not an error (such as looking up a configuration preference). Throwing an exception in these cases is not just a waste, it complicates the caller code needlessly and it deceives future readers into thinking that something very wrong occurred.

If you’re using Python (which I hope you are), embrace exceptions.

Absolutely. And Java programmers embrace exceptions just as much as Python developers (I’d argue that Java’s exception system is more sophisticated since it allows for both checked and unchecked exceptions, but let’s not digress).

I hope I’ve made the point well enough without writing a song called Raise an Exception. Whatever you do, don’t return None unless None represents some usefulness to your code.

Well… so what do we do? Unfortunately, the article ends here. At least if you’re going to criticize, offer a few suggestions to remedy the problem, will you?

Here is a scoop: exception should only be thrown for exceptional situations. Not finding a configuration value is not exceptional. Not finding a word in a document is not exceptional: it can happen, it’s even expected to happen, and it’s perfectly okay if it does.

So, what are we supposed to do when the situation is not exceptional and that, according to Marty, we can’t return None either? His post is interestingly silent on this, so let me try to offer a suggestion.

There is a design pattern known as the Null Object, which also tries to minimize the number of NullPointerExceptions one can encounter in the code. The idea is that when you are tempted to return null, you return an empty object of the desired type. This saves the user from testing for null, but it’s also fraught with all kinds of problems that I won’t get into, so it’s hardly ever used.

My advice: there is nothing wrong with returning null/None. All you need to do when you’re wondering whether you should throw an exception instead of returning null is whether the current situation is an error or whether it is expected to happen.

A default that's not really one

I have always found it ironic that Java’s default access scope (the one you get when you don’t specify either of private, protected or public) is actually the least useful (or least used).

Default access package has recently received a little bit more love when avid testers realized that it represents a good compromise between not opening your API to external users too much while making it easier for tests in the same package to access your protected state, but even so, default access scope in Java is pretty much never used.

Which is a shame, really, because this makes Java more verbose than it needs to be.

Or does it?

Is there really a scoping keyword that is prevalent compared to the other two?

If you could magically redesign this part in Java, which of private, protected or public would you make the default and why?