Modern Programming: Leaving Java – Part 2

16 02 2009

So, part 1 was all about our current circumstance in the world, with Java being a bit “dusty” (to use the term I used in the part 1 post) when held in comparison to the ideas backing new languages.

To recap the most important idea from part 1:  Java was a great step forward for its time, but there is of course the possibility of a better idea than Java.

Was the original brick cell phone the end-all solution for cell phones?  Heck no.  Was Compaq’s first laptop the best design, just because it was the first of its kind?  Absolutely not.

Just so, C and Java are not necessarily the best end-all solution, no matter how good you feel either of those languages is.

As I pointed out in part 1, there is a good legitimate use for (almost) every language, regardless of anything I say against any language.  Thus, Java will never *actually* disappear, just like C will never actually disappear.  I’m okay with that, but I wish to bring a better understanding to those of you who code in Java who would like to crucify people like me for suggesting that Java isn’t the best solution.

Part 2: Something of a Design Flaw

We all hate that diabolical moment when the sudden realization hits us: there’s a design flaw, and a project redesign is needed in order to accomplish the necessary task.  And it’s either a redesign, or you’ll be forced into more countless hours of trying to code your way around the design flaw, thus the code becomes convoluted, and making it impossible for the next guy to easily grasp what’s going on.

Part 1 was clean of any significant reference to other languages.  Part 2 is not.  You’ve been warned.  I’ve established the foundation of my case in Part 1, and so from this point of view, read the rest of Part 2  in conceptual terms.

If I get any replies on how to better code a Java example, then those persons have entirely and utterly missed the point of what is being presented (again).  If you are one of those persons, then I cry for you and your blindness to outside ideas.

Java’s core development effectively stopped the day the JVM was completed;  “That’s it, that’s all” (as the french Québecois say.. in english).  Once the JVM was made, the Java platform allowed for pretty much any package to be developed.  The JVM has all of its nasty internals tucked out of sight, and coders are free to make whatever code they want, and it’ll run on top of the JVM.  Yes, the JVM is probably tweaked frequently, but huge additions aren’t really in Java’s script (‘script’ as in playwrite).  Therefore, you have to “code around” the design in order to accomplish modern operations on Java’s data types.

This is generally the pattern of most languages: initial core development exits stage right, package development takes the spotlight.  So this being the case, we can’t really expect any overhaul to the JVM and how it works.  Therefore, I present to you concepts.

Programming is becoming more and more “object-oriented”, and rightfully so.  The goal therefore, is to make the code modular.  The goal of modular code is easy deployment/use all over the project’s code.  You change something in one main source file, and the changes are reflected everywhere.

Java (like a few other languages) has saturated (super-saturated?) itself with packages which define hundreds of specialized data structures for certain tasks.  This is great if you understand the fine nuances between their uses.  But frankly, naming two Classes “HashMap” and “HashTable” doesn’t clear anything up for me.  What’s the difference?  (Readers, don’t answer; it’s rhetorical.)

Python’s idea is a bit different: of course it provides certain data structures for you to use, but it decided to circumvent some of this madness.

So here’s the bottom line:  Java says “Pick your card”.  Python says “Write you own card”.

That’s probably a terrifying thought for you Java peoples.  “What?  No Hash generalization to plug into a [Concurrent]Map/Table/AttributeSet/Set ???!!?” And the same applies to Tree stuctures and the whole gang.

No, Python’s job is not to baffle you with finely-tuned data structures that you’ll never master.  Instead, Python’s “Write your own card” approach is used, and it’s surprisingly simple:  You’re going to write what you need to use, but we’re going to make it easy to do that.

Let’s start with something *extremely* simple.  My argument has more weight than this, but you’ll begin to understand soon.  Java did away with simple integer values casting into booleans for use in IF constructs.  Reasoning probably had to do with ambiguity between a ‘1’ and a ‘true’.  To avoid this, Java doesn’t cast ints into booleans.  Fair enough.  But then we explore the rest of how Java compares values.  To test the “value” of an variable, we’re used to using the ‘==’ sign.  The problem with dynamic object is that everything is pointers.  This means that if you ask if Object1 == Object2, you’re comparing their memory addresses which each pointers points toward.  That’s not what you want.  So by necessity, Java provides dozens of methods on each object’s base class called ‘equals’.  And so Java typically tests value by the ‘.equals()’ method.  This sort of removes the ‘==’ from its most common use!  ‘==’ is left only for FOR constructs and simple primitive tests.

Python, and a few other more forward-thinking languages, have added a reserved word called ‘is’.  This solves the issue noted above.  When you want to compare the ‘value’ of two objects, you use ‘==’, but when you want to test the ‘identity’ of two objects, you use the word ‘is’.

The point here is that if you say Object1==Object2, you’re comparing values (the most common case, you might argue), but when you want to ask if Object1 literally IS Object2 (ie, their pointers are the same), Python just makes you compare as Object1 is Object2.

Example follows. Note that in Python, examples are provided with “>>>” prefixing lines that you would type in an interactive console session. Lines without the “>>>” are things returned to you by the Python Interpreter.
# Python
>>> myInt = 1
>>> myBoolean = True
>>> print myInt == myBoolean
True
>>> print myInt is True
False

Very simply, the ‘==’ operator is used to ask the integer and boolean values if they “boil down” to the same thing. This is True. But if you ask the integer if it IS the boolean value True, then it returns False, because an integer simple ‘is’ not a boolean.

This is the kind of new stuff that Python (and other languages) are offering to the world. Java is sort of half stuck in this world of mixing the meaning of the ‘==’. If used with primitives, you test by value. If you test with any object at all, you test by memory address, and are thus forced to use Object1.equals(Object2) to test value.

Integrating custom objects in Python into standard Python syntax is amazingly easy.  By contrast, Java rather frequently forces you into writing goofy class methods to perform your tests.

Consider this example of array indexing.  The following seems natural:
// Java
String[] myArray = new String[]{"1", "2", "3"};
String myVar = myArray[0]

But if you write your own object, you can’t ever use indexing notation, to get or set items as the indexed position.  You have to use custom class methods instead.  But in Python, you can integrate with the language by defining methods on your object.  Thus, I can actually tell Python what myCustomObject[0] or even myCustomObject[“sectionName”] means:
# Python
>>> myCustomObject["mainSection"] = "hello world"
>>> print myCustomObject["mainSection"]
'hello world'

In effect, you can have your custom object manage the values however you want; that is up to you.  It abstracts the implementation so that if it ever changes, code other people have written won’t deprecate so easily, because they access the data via standard Python syntax.

 

 

Further, you can actually iterate over a custom object in your own custom way.  You can pick what “iterating over” the object means.  You have complete power. Assuming you had several “positions” in your custom object, example code might look like the following:
# Python
>>> for i in myCustomObject:
...     print i, ":", myCustomObject[i]
'mainSection' : 'hello world'
'another' : 'foobars are healthy'

Can you see the power in this?  You have the amazing ability to tell the language how to integrate very simply with the standard language syntax.

 

 

Lots of “advanced” object functionality is available to Python’s objects by default.  There’s no need to dig out obscure utility functions to get efficient functionality.  A popular thing about arrays these days are “array slices”.  Simply, this means that you can access several indexes of an array at a time. In Python, your typical idea of an ‘array’ is implemented as a data type called a “list”. This is built into Python automatically. There’s no need to import any goofy package first.
# Python
>>> myList = ["a", "b", "c", "d"]
>>> myList[0]
'a'
>>> myList[0:3]
['a', 'b', 'c']
# You can also imply the beginning or end of the list:
>>> myList[:3]
['a', 'b', 'c']
>>> myList[1:]
['b', 'c', 'd']
# Or, you can go backwards:
>>> myList[-1]
'd'

See how easy this is?  Say goodbye to excessive myArray[myArray.length – 1] calls.  Lists support pushing, popping, removing specific items, and queries to find out if an element exists in the list:
# Python
>>> myList = ["a", "b", "c", "d"]
>>> myList.append('e')
>>> myList
['a', 'b', 'c', 'd', 'e']
>>> poppedValue = myList.pop()
>>> poppedValue
'e'
# Pop from an index:
>>> poppedValue = myList.pop(0)
>>> poppedValue
'a'
# Append lists together:
>>> myList.extend(['1', '2', '3'])
>>> myList
['b', 'c', 'd', '1', '2', '3']
>>> "b" in myList
True
>>> "z" not in myList
True
# As a side note, you can do the same to any iterable object, including strings or custom objects!
>>> myString = "12345"
>>> myString[2:4]
'34'
>>> myCustomObject[1:]
['foobars are healthy']

Much more is possible, but this is good enough to start with.  Just understand how amazing simply Python has made this.  Java is a nightmare compared to this.  It might all seem trivial to you, but Python has decided what the most effective way to perform these operations is simply built in.  Anybody caught using any loops in Python to do these things should be arrested.  Anybody caught using loops in Java to do these things is doing it because they have no choice.

 

 

These examples only touch the surface of the differences.  These differences are exactly what makes modern programming languages so powerful.  Yes, there’s a speed trade off, but the productivity to be gained is incredible.  The “scaffolding” of Java and C is overdone.  It is not as needed as it once was.  Python’s clean appearance is easy to read, easy to maintain, and easy to extend.  Python is fully object oriented, and supports multiple class inheritance.  Complex tasks are easier, and you’ll find that you don’t need to code with your browser open to the current JavaDocs.  Python’s just easier.  I’d love to expound on more features of Python which further enhance productivity, so I’ll probably write a Part 3, for those curious to have it explained.

The point is not comparing speeds.  The charts often prove that Java can outrun Python in many tasks.  But as you look at the code to power the Java part of the test, and then compare it to the Python equivalent, you’ll be shocked at how little effort is required to achieve the same behavior.  And with those clock cycles lost in the Python code are more than made up in productivity, allowing you to simply accomplish MORE.  Certain tasks will still require C, regardless of how good Java is.  Nobody seems to complain between the slowness of Java compared to C.  Thus, it’s not a big step to move on to Python.  Modernize.  Get more done.

Until part 3.

Advertisements




Modern Programming: Leaving Java – Part 1

15 02 2009

I recently wrote about “Why Java is stupid”; the responses were interesting, found both here and on other aggregating blog sites.  I intentionally was a bit uncensored in my post, and it became obvious that the point was being missed.

I’m going to backtrack, and try explaining myself again, though this time with more directed arguments and reasons.  I’m also going to break it up into a few parts (at least 2), so that it’s easy to understand the isolated concepts in each part.

In addition, I will completely leave out the mention of any other language (except for simple references to their existences) so that readers may avoid misunderstanding the point being  made.

Part 1: Time Will Tell

Over time, it becomes clear why certain technologies were good or bad; with time, we begin to see the mistakes we made early on.  When the technology first debuts, we use it because its new.  Then, as time goes on, we begin to see where improvements could have been made.

A few examples:

  • Laptops, like the Epson HX-20 mothership herself, or maybe the first Compaq portable shown here and here.
  • Zip disks: a victim of timing and rapidly advancing technologies (of which technologies the Zip disk was not a part).
  • Cell phones: Clearly the technology has developed since the days of the “brick” phones, which unfortunately is only recently in our past.

So clearly good ideas were present in each of those examples, but the technologies are now radically different than when they first came out.

What changed?  Sure, we made the parts smaller.  Of course, we changed the casings to look more sleek.

But what REALLY happened?  Here’s what changed:  Laptops now have dual core processors.  You can buy 16gb flash SD cards for under $50, and solid-state harddrives are finally pushing their way into the market.  We’ve got cell phones that double as music players, and triple as GPS systems, and are becoming development platforms, as with the Apple iPhone, and Google’s Andriod-powered phone.  For crap’s sake, we have OPEN SOURCE *phones*, and we read our email on them.

Its obvious that the core functionality of those technologies has been radically redone.  We didn’t just slap a new face on cell phones in order to get them to where they are now.  The fundamentals were rethought.

However, some things just simply seem to lag a little bit behind in our vast Information Age, where the ideas backing the technology seem to be slightly out-dated.

To be fair, those technologies (dusty or not) will still have their uses.  The Verilog programming language IDE— holy heck that’s a hard buggy thing to use.  It would benefit from a makeover.  But we don’t do that because too many things rely on the situation as it currently is.  Changing it would probably only create more troubles than its worth, one might argue.

But here’s an example of a technology that actually holds a massively large part of our programming playing field: Java.  Java is far more prestigious than Verilog (thank goodness), yet it seems to be suffering from its failure to imp lament more modern programming ideals.

Java, by nature, is remarkably similar to C++, given some basic syntactical differences.  It was designed to be C++++, if you will; conceptually it didn’t stray far from what the world knew and loved (that’d be C), yet had the advantage of executing itself on any platform for which a JVM was created.  It was a marvelous step forward into the fairly unknown territory of abstraction of programming into layers.  It took away the nastiness of having to manage your own dynamic memory, with “destructors” and such.

And Java became popular.

And this comes at no complaint from me, I assure you.  The problem arises, however, when 6 or 7 years go by, and we realize that there are better conceptual models.  Staying “fair”, various models have their various specialized usages.

  • Perl – made for rapid development of quick’n’dirty tasks.  Programs of the target size wouldn’t benefit from being compiled anyway, so this scripting language made sense.  It’s problem is said to be that it is “write-only” code.
  • PHP – designed for amazingly flexible web developement, where users could escape CGI and actually run a markup preprocessor at good speeds.  It specifically avoids certain annoying cache issues.  It’s problem seems to be that it was *not* designed initially to be an object-oriented language.
  • C# – The ‘C’ alternative to Java.  It’s conceptually the same idea as Java, though its syntax kind of strays from what the world has been used to.  Boasts faster speeds than Java, running at “almost” (whatever that means) the same speed as native C code.

And the list could go on.  Each has its use.  Each has its flaws or weaknesses.  Java is not exempt.

The concept of the JVM was miraculous.  That’s the sort of thinking that progresses the information age.  But as we explore new technologies, coding in Java for small simple tasks is far from the best option.  You’re much better off just tagging a lighter-weight scripting language to do your task.  There’s almost no sense going through the burdensome process of defining separate files for just a few simple class objects, and then one more class object (and file) for just your static utility methods, and then possibly another class/file to server as your program’s entry point.  That’s silly.  Just script it and get the task done.

The “Just script it” method is great, because it removes the needless, never-changing parts of writing in C or Java– you just worry about the task, and the scripting language alternative will worry about getting it done.  This method often suffers a bit in speed, but we’re no strangers to that trade-off.

Take this example: Computers work on “synchronized” designs, where everything is controlled by one common “clock” signal.  It ensures that everything is coordinated, so that if one part of the computer finishes its task before another part, you avoid “race conditions” where there’s no absolute guarantee as to which of the computer’s tasks it will finish first.  If the computer can’t predict which will be first, then you’re bound to have a very very unstable computer.  The cost of having a synchronous design is that we suffer from a little bit of slowdown.  However, the opposing “asynchronous” idea is mass chaos when aimed at a design of the complexity of a full desktop computer.  If tediously designed, yes, it may be possible to create an asynchronously clocked personal computer, but would the effort be worth it?

So that’s what it comes down to:  Is all that extra effort worth it?  Lose a little speed, gain productivity.  The argument is that there is a diminishing return on a function f(x)=y, where ‘x’ is the time put in, and ‘y’ is the results.  Eventually you get to the point where a huge amount of effort is required, just to get a small more amount of ‘better’ results.

Java is a strange case, because it’s interpreted, yet it’s verbose.

It can be fast, but the methods that actually do the dirty “fast” work are hard to read and are packaged up into shadowed utility packages in the dark corners of the language, and you’ll be scolded by Java junkies about how to “do it better”, which only proves that you have to be a junkie to know about the good fast utilities.

It’s big JVM is possibly a little *too* big, and it very quickly rules Java out of module-based web programming (where a server like Apache just calls a Java process to run your Java code).  So instead, we’ve developed “solutions” specific to Java, like Tomcat, Glassfish, and a few other such things to accommodate the ragingly popular Java.

And here’s where we ask ourselves, in light of Java and its world-wide influence:

Is there a better way?

I submit that there is.  More to follow in Part 2, yet to be written.