Subscribe to <rant />        RSS Feed
-----

Random Rantings about Java in the World of Education

Icon 1 Comments
***DISCLAIMER***
BY READING THE BELOW, YOU,
HEREAFTER REFERRED TO AS THE
READER, AGREE NOT TO FLAME
THE POSTER OF THIS BLOG.
DISAGREEMENT IS ENCOURAGED,
BUT GROUNDLESS UNSUPPORTED
NEGATIVE POSTING WILL NOT BE
TOLERATED. AS THE POSTER
HAS NO ABILITY TO ENFORCE
THIS AGREEMENT THE RESPONSIBILITY
OF COMPLIANCE IS LEFT TO THE
READER AND HIS/HER HONOR. THESE
OPINIONS ARE NEITHER THE OPINION
OF </D.I.C> NOR THE PROGRAMMING
COMMUNITY AT LARGE.

Thank you for reading :)

To begin... Alright, i know that the few of you who remember me from when i was active on the forums know i have a bit of a reputation concerning java, so take what i say with a grain of salt... or not.

Here's the blog portion. A few weeks ago i was passing by an AP CompSci classroom at a high school, and the teacher was telling the students they should not use recursion because it is inefficient. The program on the board was like this:

class recursionTest {
   public static void printHello(int n) {
      if (n>0) {
         system.out.println("Hi!");
         printHello(n-1);
      }
   }
   public static void main (String[] args) {
      printHello(100);
   }
};



The fact that a teacher would tell them not to use recursion should insult any functional programmer reading this :)

Here's my problems with this mentality:
1. Premature Optimization is the ROOT OF ALL EVIL. 'Nuff said.
2. Optimization outside of program choke-points/bottlenecks is near-useless (corollary of #1).
3. This call would be bytecode-level optimized by ANY half-decent compiler in the 21st century because it's tail recursion!

Expanding upon this, this is just one example of how Java is teaching people lies and falsehoods in the name of ease-of-use and not daring to make anyone actually think (especially in the intellectually challenged world of programming :P). For example, say instead of bytecode we were outputting to assembler. This is what somebody would think happens (not perfect ASM code, but is a valid comparison to what the bytecode would look like):
SECTION .data
hi_msg:
   db "Hi!",10
hi_msg_len:
   equ $-msg
SECTION .text

main:
   push dword 100
   call print_hello
   pop ecx
   
   mov ebx,0
   mov eax,1
   int 0x80

print_hello:
   push ebp
   mov ebp, esp
   cmp [ebp + 8], 0
   jz exit_func
   dec [ebp + 8]
   mov edx,hi_msg_len
   mov ecx,hi_msg
   mov ebx,1
   mov eax,4
   int 0x80
   push [ebp + 8]
   call print_hello
exit_func:
   pop ebp
   ret


Let's take a second look at the last few lines of the calling function. Instead of pushing and popping, most compilers will replace push [ebp + 8] call print_hello with just a jmp print_hello (its not that simple, but that's the gist. It takes away all the stack fiddling) since everything's already set up stack-wise. This is called tail recursion. All that playing with the stack and calling the function 100 times is GONE! *gasp* what do we do now that our first argument has broken down?

Now for a third look. Everyone see the int 0x80 in print_hello? The time that it takes for the kernel respond to the interrupt, to receive the information to output, see that we're running in a terminal so we don't need to change VGA, forward the output to the xserver (which then needs to figure out what to do with it and display it), update the display once the xserver's finished working, and return to the program is HUGE compared to the time to pop one variable on and off the stack a few times. Add this to the fact that Java is running through a virtual machine, so we're adding another step in, and we've got a HUGE performance bottleneck on our hands at this point. Honestly, if we're worried about the time/memory it takes to push/pop a few variables (which doesn't actually happen, see above), 1. we shouldn't be using java, and 2. you must be using a 1980s era computer that has less power than a TI calculator.

Let's take memory management. It's a wonderful tool if you know what you are doing. However, it's easy to run amok when you're shooting fire-and-forget. We should still know about scoping and the like, destruction, etc. If we're using a reference-counting system it's not smart to make a million references to the same object and keep them all in scope for the duration of the program. If you're using a garbage collected system, don't expect the collector to be reliable if you need the timing to be precise. Making false assumptions about code causes bugs. Know the number one way to confuse and annoy a student? Tell them that their code is theoretically right but it doesn't work in all circumstances.

So, to get to the big, broader point- why are we teaching students all these ideas and concerns when these are mitigated by the neglected nitty-gritty of the bare metal and the collective work of a TON of people much smarter than us? Just teach C! In the modern day, cool ideas like object-orientation, functional programming, automatic memory management, etc., etc., (insert pet feature here), etc. have made our lives as programmers much, much faster and easier. However, we should have an idea of how our code will actually be run on the machine and how it will impact performance. Even with very high level languages, you can still kind of tell what is going to happen behind the scenes with a solid grounding in the lower-level details. Sure, there are unforseen results. However, just because we are able to not pay as much attention to detail doesn't mean we should neglect it entirely! If i'm writing a program to calculate the mandelbrot set, i shouldn't care much about the value of registers and system calls and the like, but i should know that my performance bottlenecks are going to be in the fact that we're iterating a few million times, so the algorithm shouldn't have any more +-*/ etc than it needs to, and we need to find an efficient way to display the data- cause picture formats are huge. OTOH, if i'm creating a network library, i need to know that my choice of protocol is going to have a huge impact on performance and packet reception, and that improving the millisecond of latency when acquiring or closing a connection really isn't worth it compared to the huge gains i could make by improving data packing/unpacking- but i don't need to know the actual format of the structs i'm working with if that's abstracted away, as long as i can get the data. I also need to know about locking data when i'm sharing data between connections, even if this is abstracted away, because i don't want to accidentally work in a way that gets around the language's built-in mutexes.

So that's the end of my big rant against unnecessary abstraction and not knowing what we're abstracting away. To quote Joel on Software, "The only way to deal with the leaks [(bugs)] competently is to learn about how the abstractions work and what they are abstracting. So the abstractions save us time working, but they don't save us time learning."

Thanks for reading.
</rant>

1 Comments On This Entry

Page 1 of 1

NickDMax Icon

14 April 2010 - 03:12 PM
Well, first off I would like to point out that, "Premature Optimization is the ROOT OF ALL EVIL" refers to making solid design decision before "optimizing" code. -- it is not the "ROOT OF ALL EVIL" to choose a merge sort over a bubble sort when the number of items sorted may be greater than 100. This is not "optimization" it is "design".

Of course the instructor here was probably in the wrong. There are many design reasons to favor recursion over iteration. For example some recursive algorithms are HIDEOUSLY complicated when written iteratively yet refreshingly simple when stated recursively. So while one is welcome to argue efficiency all day, I for one would rather do the implementation in the clearest and simplest form. I would also argue that the efforts made to convert recursive algorithms into iterative ones will result in a less efficient solution.

Of course the example given is pretty bad for the case of recursion... but ask the instructor to implement an efficient version of some of the classic recursive algorithms and see what gets said.
0
Page 1 of 1

Trackbacks for this entry [ Trackback URL ]

There are no Trackbacks for this entry

January 2018

S M T W T F S
 123456
78910111213
141516 17 181920
21222324252627
28293031   

Tags

    Recent Entries

    Recent Comments

    Search My Blog

    0 user(s) viewing

    0 Guests
    0 member(s)
    0 anonymous member(s)

    Categories