Showing posts with label python. Show all posts
Showing posts with label python. Show all posts

Tuesday, February 9, 2016

Project Euler Problem 1 - In Python

Project Euler

Project Euler is a web site with hundreds of problems for you to tackle however you want to solve them. Some of them, if you are sufficiently adroit mathematically, can be solved on the back of an envelope. Most of them clearly need a piece of software to grind through the calculations. You can use whatever programming language you prefer. the site asks only for the answer. Each problem yields a numeric answer. If you provide the correct answer, the site credits you for solving the problem and grants you access to a discussion page. The discussions are mostly people bragging how they solved the problem. The bragging isn't anything important, but it can be useful to look at other people's approaches to see other ways of looking at the problem that perhaps hadn't occurred to you.

The one "guideline" is that a good solution should need no more than a minute of time on your computer. If your solution needs way more time than that, then you should look for a better solution.

Tell Ya What I'm Gonna Do...

I'm going to show you how to solve some of the project Euler problems using the Python 3 programming language. Instead of having you install Python 3 on your computer, I'll be using the "Python in the cloud" facilities of pythonanywhere.com. You can sign up for a free account of your own there. For small programs like ours, they offer their service for free. If you use their site to build something that becomes enormously popular (say, the next "Farmville" game), you'll be needing to pay for their services, but we're far, far from crossing that line between trivial computing load and significant computing burden.

It'd be useful if you figure out a good way to prepare your Python programs in a file, but you can start with notepad or whatever simple editor you are most comfortable with. If you tell us in the comments on this blogpost what editor or IDE ("Integrated Development Environment") you prefer, it may influence whether I write future articles addressing that editor or IDE.

Project Euler Problem 1

The first problem on project Euler is one that calls for very little code. I'll tell you that I approached the problem as a computer programmer, but in the discussion page for the problem there were people who knew how to compute sums of a series using a simple formula and they were able to readily solve problem 1 using only pencil and paper. That's just proof that although I've worked with mathematicians, I'm a software guy, not a mathematician.

The crux of problem 1 is: Find the sum of all the multiples of 3 or 5 below 1000.

The example given makes clear that they are only asking us to consider positive integers. So no need to worry about negative 3 and negative 5 and so on. ("If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.").

Spoiler Alert.

I'm going to talk here about how I solved the problem. If you want to solve the problem on your own, stop reading here and go solve that problem. Feel free to come back later and tell us in comments how your solution is better than mine. Better in what sense?

Solving Problem 1 in Python

At this point, I am tempted to show you the small program that I used to solve the problem, but that is so small a program that you'd probably glance at it and walk away grumbling "nothing to learn here", so I've decided to creep up on the solution a bit more slowly. I hope you pick up some comfort with Python programming along the way.

The General Shape of the Program.

Generally, the way to write a program is to start out with a rough idea of what the program should look like. You can write this down in "pseudo-code" - a mixture of your native language and whatever bits of programming language structure you are comfortable to stir in. One of the delights of Python is that Python code looks a lot like pseudo-code, so if you nudge your pseudo-code into being real Python code, you can test out your pseudo-code by running the program. When it works, perhaps you are done, but if your actual target language isn't supposed to be Python, then you have a working prototype that you need to re-code into your intended target language (Perhaps C or C++ or even some assembler language). It is worth noting that in the real world, often a manager faced with a working prototype that works well enough, will suddenly decide that a Python implementation is plenty good enough to declare the problem solved, even if its the first instance of Python code admitted into "production" use in that shop.

This program is going to need an iteration (loop) to consider all the natural numbers less than 1000. And inside that loop it is going to need a conditional statement (if statement) to select the numbers that are multiples of 3 or of 5 (which for whatever reason are the numbers that this problem considers to be interesting). And for the numbers that are multiples of 3 or 5, we'll need a little arithmetic to accumulate the sum of the selected numbers.

There's more than one way to do it. For example, we could loop through all the non-negative integers <1000 and build up a list of the numbers that meet the criteria of being "interesting". Then we could take the sum of that list to get the desired answer. But we have no further use for the list in this problem, so I assert it is simpler to just accumulate the sum as we go.

Another approach would be to generate the multiples of 3 and to generate the multiples of 5 that are less then 1000, and then tally up the generated lists, but you'd need to be careful not to include any numbers twice. Some numbers (e.g. 15) are multiples of both 3 and of 5, but only should get added into the sum for this problem once, so I assert it is simpler to just consider each of the candidate numbers and accumulate the ones that meet the criteria for being interesting.

Got another plausible shape for the solution this problem?

So, I'm going to stick with my initial proposal which in Python-like pseudo-code looks like this:

sum=0
for num in numbers 1 thru 999:
    if num is "interesting":
       sum += num
print(sum)

Note that in Python, indentation is used to delineate the blocks of code. My Python-like pseudo-code follows that same convention. Thus the body of the loop statement is indented under the "for" that introduces the loop. The body of the "then" clause that is made conditional by the "if" statement is indented inside the "if". Since the "if" is inside the "for" loop, the accumulation of the sum is doubly indented. The initialization of sum to zero is outside of the "for" loop so it isn't indented at all. The "print" statement is also not indented. We don't want to print the partial sum on each iteration of the loop, so it is important not to indent that final "print". But maybe when you are debugging, a print statement inside the loop would be a helpful addition. That would be done by adding another print statement and indenting it so it is inside the loop. You might want to include a comment on your debugging code so you can trim the debugging code out when your program is in good working order.

The "sum += num" statement is Python short-hand for "sum = sum + num", since accumulating totals is such a frequently needed operation.

I hope you've noticed that the pseudo-code is not quite working python, so we aren't done yet. The most glaring magic is how do we really decide if a given number, which we've named "num", is "interesting"?

How to test if a number is a multiple of some value

So we need to consider how to test a number to see if it is a multiple of 3 (or of whatever number we want to test to see if it is a multiple of). Python has a modulo operator (%) that is documented here. x % y is how you ask Python to compute the remainder of dividing the number stored in x by the number stored in y. So all you need to realize is that if x is a multiple of y, that the remainder will be 0, and if x is not a multiple of y, then the remainder will not be zero.

So if we have a number to test named num, then we can test if num is a multiple of 3 by using this Python code:

num % 3 == 0

The result of that test expression is a True or False value (True if the remainder is 0. False if the remainder is not 0). But we want to know if the number is divisible by 3 or is divisible by 5. Happily, Python has an "or" operator that will let us combine 2 True/False values in exactly the way we need.

Here's a copy/paste of my PC anywhere session where I tried this out:

>>> num=27
>>> num % 3
0
>>> num % 3 == 0
True
>>> num % 5
2
>>> num % 5 == 0
False
>>> num % 3 == 0 or num % 5 == 0
True

As you can see, the Python rules for operator precedence did exactly the right thing for us here, but I find that long expression a bit hard to read, so I added some un-necessary parentheses to make it easier for a human to parse.

>>> (num % 3 == 0) or (num % 5 == 0)
True

How to conjure up a list of numbers?

In many programming languages, Fortran for instance, the way you conjure up a sequence of numbers is you have a variable to serve as a counter. You initialize the counter to a starting value, then you increment the counter to get the next value and you need a test to decide when you've gone as far as you want to go. If you've programmed in C, that's what a "for" loop in C does. But there's a more Pythonic way to do this in Python, so please take care not to write Fortran (or C) code in Python syntax. A Python "for" loop looks like
for x in list:
    do something with x
Where x is an arbitrary variable name that takes on each of the values in the list and the body of the loop (which I've represented as "do something with x") processes each of the values as x is stepped through the list.

If you want to read more about looping in Python, especially if you are comfortable with looping in other languages, I strongly recommend Ned Batchelder's blog post "Loop like a native".

Not only does Python have a statement to consider each of the values in a list of values. It also has a built-in generator of a list of values. In Python 2, "range" is a built-in function to return a list of integers, but such a list takes up space. So "xrange" was introduced to return a generator that'll provide the desired sequence of integer values on demand without ever actually creating the list as a whole in memory. xrange worked well enough and explaining the distinction between range and xrange was ugly enough that in Python 3, xrange became range and you only need to know its a generator if you're interested in the details of how stuff works. So just say range(1000) to conceptually whip a list of numbers 0 through 999.

So now our pseudo-code has morphed into runnable Python code:

sum=0
for num in range(1000):
    if (num % 3)==0 or (num % 5) == 0:
       sum += num

print(sum)

And we're done, except for running the code to get the answer. I'll not reveal the numeric answer here, so please learn how to run this yourself.

Mystified? Please tell me if I've confused you so I can polish things up before my next blog post.

Saturday, September 27, 2014

Actual code - C vs. Python for a small problem

If you aren't much interested in writing software, this post is probably not for you. If you read the post without following the links to the example implementations, then I'm not sure what you are doing here, though you are certainly welcome to ask questions.


Recently on Quora.com someone asked to see C code to find the first 20 prime numbers. Seemed like an easy enough question, but the first guy who answered it, gave a C++-based pseudocode and some tips on how to convert that to C. That answer didn't make me happy. Heck, I figure if you're going to write in some other language, why not Python as a sort of testable pseudocode, but the question really needs that answer to then be re-stated in C.


So I sat down and banged out a Python program to find and print the first 20 prime numbers. That code is here: find20primes.py


I used a list to hold the list of primes. When the list grows to 20 items, I'm done. I start the list by telling it 2 is a prime number. I then only consider odd numbers as additional candidates. If the candidate is divisible by any of the prime numbers we've found so far, it is not a prime number. If the candidate isn't divisible by any of the prime numbers we've found so far, then the candidate is a prime number so we add it to our list of primes and, in ether case, add 2 to the candidate number to get the next candidate number to be tested. In C, we'll need a little more book keeping for the list, but since the max size of the list is bounded (20 items), things should translate from Python to C pretty easily. One trick that isn't entirely obvious is the use I made of Python's for...else control structure to catch the case of the for loop not exiting via break. We can paper that over with a goto in C, or you can add some flags


I was thinking that C has labeled break statements to let me do sort of the same thing as that for...else. But much to my chagrin, that's a feature of Java, not C. Oops. So, goto it is in my C translation of the program.


So I sat down with that Python listing open in one window and typed up find20primes.c That code is here: find20primes.c


I believe it is a straight-forward translation of the Python program into C. Of course, the C program is bigger in the sense of it has more lines of code. There are lines added to delimit the blocks and loops in the program, and lines added for variable declarations and lines added for the annoying book-keeping that C needs me to do where Python just handles those chores. I did run into some trouble where I didn't get the book keeping entirely correct the first time through. The program outputted 20 primes, but it started with 2, followed by 73, followed by 3, and it left out 71 at the end of the list. Huh? Turned out I was mistakenly incrementing primecnt before I'd used it to fill in the next slot in the primes array, so I skipped the primes[1] slot and just got 73 there by bad luck. Python would have told me about an uninitialized variable if there'd been a spot in the Python program for me to have committed that same kind of error.


Having finally gotten both programs working, conventional wisdom is that the C code should be much faster than the Python code. So I used the "time" command to see how the timings compare.


Using cygwin Python 2.7.8 on Windows 7 on a PC with an i5 processor and 8GB of RAM,

$ time python find20primes.py

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71]

real    0m0.136s
user    0m0.000s
sys     0m0.062s

Using cygwin cc 4.8.3 on that same Windows 7 PC:

$ time cc find20primes.c

real    0m0.238s
user    0m0.045s
sys     0m0.185s

$ time ./a.exe
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71

real    0m0.064s
user    0m0.015s
sys     0m0.015s

The execution time for the compiled C program was way less than the total time for the Python run, but if you add in the compile time for the C program, Python comes out ahead. Your mileage may vary.


By the way, if I throw in a -O option ("optimize the generated code") on the cc command, it further slows the compile down, while the run time is about the same.

$ time cc -O find20primes.c

real    0m0.336s
user    0m0.031s
sys     0m0.185s

$ time ./a.exe
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71

real    0m0.086s
user    0m0.000s
sys     0m0.015s


(the "real" elapsed time varies a lot from run to run. These run times are so short the variability makes it hard to make fair comparisons in races between the programs). I suspect that the real time is dominated by the console I/O to print the results, so optimizing the details of the loops isn't going to do much improving of things.


Now to make things more interesting, suppose I wanted to pass in as a command line argument the number of primes to be found. So long as the primes are still in the range of ints that only needs a malloc of the array in C but if the program is ever asked to get up into really big primes, the Python code will keep on chugging while the C code will need substantial rework to pull in an arbitrary precision integer library module. This blog article is already long enough, so I'll leave that generalization to "findNprimes" up to you. How big does N have to be to break the C code's use of ints? I suppose that with relatively minor surgery, you could convert over to use of long ints (or if your compiler supports them, to long long ints) in the C program. Looking into it lightly, it appears that the cc included with Cygwin supports long long ints. The format strings will need adjusting. Use %lld instead of %d.


If you've feeling anxious to try further experiments, see how pypy does in handling the find20primes.py program. That'll probably be more interesting with findNprimes.py with a really big value for N.


The moral to the story is that C may not be the best choice of programming language for this kind of problem.


Did you enjoy this article or was it too technical? Please add a comment down below so I know what you think about this sort of writing.

Wednesday, August 13, 2014

Getting more familiar with Python Classes and Objects.


If you've been following this blog, you're aware that I feel unprepared to make good use of the Object Oriented Programming facilities of the Python programming language. Python is kind enough to allow programming in non-OOP styles, but Python's OOP features keep glaring at me, reminding me of what I don't comfortably know.


I posted a question on Quora.com asking for real world examples of multiple inheritance being used in Python programs. I was disappointed about how few answers came back. That dearth of response left me with the suspicion that I'm not the only person around who isn't completely comfortable with multiple inheritance. http://www.quora.com/What-is-a-real-world-example-of-the-use-of-multiple-inheritance-in-Python. Looking around at other multiple inheritance questions on Quora (http://www.quora.com/Why-is-there-multiple-inheritance-in-C++-but-not-in-Java), I see some reason to suspect that super serious application of OOP is just going to need more time to sink into the heads of the majority of developers. So, I'll continue to watch and learn, but will try to remember to adhere to the KISS principle to the greatest extent possible.


Additional Lessons


  1. This 40 minute video from Ray Hettinger (The Art of Subclassing) explains how Python classes differ from classes in other languages. Ray tries to reshape people's thinking here, so if you aren't already deeply steeped in OOP lore, you may feel he's dwelling on the obvious. He may give you some ideas of appropriate uses of inheritance in Python objects.


  2. Ray mentions this 2nd talk in his video. This 2nd talk was the next talk after his at Pycon 2012. "Stop Writing Classes", Jack Diederich, 28 minutes. Basically, that video asserts that my own example so far of writing a class for a Python program is not very good. The clue: My example class had only __init__ and one other method. I could have written it as a simple function and used the partial function from the library functools module to handle the initialization.


Further Reading


I have 3 previous blog articles on OOP in Python.


In Creeping up on OOP in Python - Part 1 I described a use of an object-oriented library module, pyparsing, to solve a Project Euler problem.


In Creeping up on OOP in Python - Part 2 I reworked my solution to add a simple class of my own. I was happy that introducing that class made the code cleaner to read. But if you watched the "Stop Writing Classes" video given up above in this blog article, you'll probably notice that my class is an example of exactly what they say you shouldn't do.What can I say? I'm still learning this stuff.


The 3rd in my Creeping up on OOP in Python" series was a bit different from the first 2. It explored an academic question about multiple inheritance. It is exactly the kind of A, B, C example that Ray mentions avoiding in his talk. Creeping up on OOP in Python - Part 3. I haven't forgotten my promise of a Part 4 as soon as I have a practical example of multiple inheritance to substitute for A, B, C and D in that academic question. But so far, there is no Part 4.


Ray mentions "the gang of 4". If you aren't familiar with them, here's a reference for you to pursue: http://en.wikipedia.org/wiki/Design_Patterns. And he mentions "Uncle Bob". I also mentioned Uncle Bob, with some links here: SOLID software design.


Know more about this OOP stuff then I do? Well, don't keep the info to yourself. Please post a comment with a link or example to help me learn more. Have you found a particularly relevant MOOC that you'd suggest?

Saturday, August 2, 2014

Python and Parallel Processing

(Image taken from http://www.ibm.com/support/knowledgecenter/SSEPGG_9.5.0/com.ibm.db2.luw.admin.partition.doc/doc/c0004569.html without explicit permission, but with acknowledgement of the source of the work).


I've written about Parallel Processing here before. e.g. See "What's the fuss about Parallel Processing?". I've been worried by my reading that seems to predict that imperative languages such as Python will never be able to safely cope with massively multi-processor architectures in the future. The "Downfall of Imperative Programming Languages" basically says that functional programming languages (such as Haskell and Erlang) are going to be the way of the future. I've been trying to get my head wrapped around Haskell, but so far without much success. So I was happy to hear a clear call from the Python camp that "I'm not dead yet!".


The article that gives me new hope is "Parallelism in One Line" the gist of which is that "Sure you can use the threading library to manage pools of threads (or of processes), but that takes a lot of lines of code and is very error prone, but there's another way to do it." The other way to do it is to use a parallel version of the map function. I, for one, didn't know that there's more than one version of "map" available in the Python library.


If you do a Google search for:

Python map

you will readily find documentation for Python's standard (iterative) map routine. e.g. "Python 2.7.8 builtin functions documentation - map".


If you readily want to find documentation of the parallel version of map that the Parallelism in One Line article talks about, you need to modify your Google search to:

Python map multithreaded

which will take you to a subset of the first search. I was amused to find among the search results a 2010 ActiveState Recipe for building your own "concurrent map" function, which drew a comment from one reader asking why not just use "multiprocessing Pool.map". The recipe's author admitted not knowing about that one.


From that 2nd search I found "Multiprocessing - process based threading documentation". It does worry me that the documentation seems to have more complexity and gotchas than the Parallelism in One line article owed up to. Arguably I shouldn't be blogging about this at all until I've actually given it a try myself (but I still don't have a multi-core processor here at home).

It's a trick?


If you've been reading this carefully, you might rightfully object that it's all a bit of a trick. The map function is an element lifted from the world of functional programming and then provided in Python. The parallel version is only safe in Python if the function that you are mapping is "pure". If the function code has side-effects, then you will have race conditions and potentially suffer horribly at the hands of multi-cores. The language isn't going to inherently protect you so you have to be careful out there.


If you want to read more about the challenges of Python vs. multi-core architectures, see "Python's Hardest Problem, Revisited", by Jeff Knupp. The piece parts to roll your own multi-processes or multi-threaded Python program remain available, but be sure you have plenty of iodine and bandages on hand if you cavalierly venture into the world of multi-cores in a language that makes no promises of (much) concurrent processing safety. Design your code carefully and watch out!

Monday, February 3, 2014

Python Generators

Background

Back in May, 2013, I posted "Cheap, but not Free, Modular Code has a Price". In that blog article I compared the performance of my solution of Project Euler problem 14 to the performance of Nico Ekkart's solution of that same problem. As I explained in that article last May, Project Euler's guidance on performance is that a solution should be able to complete on a typical PC in less than a minute. My initial solution ran well over a minute and I applied a cache to speed my program up. Once I'd gotten it down below the one minute limit, I had concluded "good enough" and went on to other problems. But Nico honed his solution a little tighter and outperformed my program by a factor of 4.


Looks to me that we had basically the same solution, but his was more of an in-line implementation, while I used a Python generator to produce the sequences of numbers the processing of which is the heart of problem 14. I concluded that the Python structuring facilities like generators do add overhead but I opined that the added clarity of packaging the sequence generation as a "generator" made the overhead worthwhile. Nico's code for his cache was so little code that I didn't really defend my use of a Python "class" for my cache implementation. Some further experiments with the code to determine how much of my extra overhead came from the generator vs. how much came from my cache implementation might be interesting. I've posted the source code and invite you to experiment and share your findings.


But that isn't what I came here to talk about today

This blog post today is aimed at expanding your knowledge of Python Generators and share with you a neat trick that I've recently learned: a generator of dictionaries.


Python Dictionaries

Back in January, 2013, I posted "Dictionary Implementation". In that article I pointed to where the Udacity CS101 MOOC introduces Python dictionaries and pointed to further places to look to learn how Python implements dictionaries, hash tables. If you aren't comfortable with Python's notion of a dictionary, I'll sum it up as an easy to use collection of name-value pairs, much like an array is an easy to use collection of subscript-value pairs.


Given an integer value as a subscript into an array, you can easily ask for the value associated with that subscript. (In Python such an array is called a "list". But if you have a dictionary of name-value pairs, in Python it is easy to ask for the value associated with a name. e.g. What value is associated with "eggplant", where "eggplant" in this example is a possible "name" entry in the dictionary. If this is all still mysterious to you, my suggestion is to dig for more info on the web. Google search is your friend. A Google search for:

python dictionary

turned up more than 5,000,000 web pages today and Google looks to have done a decent job of sorting the most helpful ones to the front of the search results.


Or perhaps you should work your way through Udacity CS101 to learn this concept of dictionaries and more.


Python Generators

But as I already said, the topic of my blog post today is Python Generators. Rather than take the time and trouble to create a fresh new tutorial about Python Generators, I'll pause here to provide a link to an article from April 2013 from Jeff Knupp: "Improve your Python: 'Yield' and Generators Explained". That article resonated with me as written in an easy to understand way. It's about 19 screens long, so it isn't a quick read, but you can get back to Facebook and YouTube later.


Knupp's article should certainly get you to the point of being comfortable with my Project Euler problem 14 generator. My generator is very vanilla, just conjuring up a sequence of numbers. The one tricky aspect is my program often doesn't pursue the sequence to the end, but sometimes decides it needs to see a new sequence. I was a little nervous when I did it that way, but now understand that Python doesn't mind dangling generators like that, and even should know enough to be able to garbage collect their saved state, if memory gets tight and it is clear that there's no way the program could get back into that old sequence. Powerful stuff and a feature unlike anything available available in C, Fortran, Basic or Cobol to name 4 examples of older more traditional programming languages.


But Wait! There's more!

If you've read this far but are yawning, thinking that hardly ever do you, yourself, have occasion to use complex logic to generate a sequence of numbers in the programs that you write, well hang on and see what else generators are good for.


Igor Vasilcovsky recently pointed out to me an interesting tutorial from David Beazley about generators. The meat is the slide deck under the presentation link on that page. Even with 2 slides to a page, that slide set runs to 79 pages so it probably is too much to absorb in one sitting. So try to work through it in several sessions. Here's my summary of the key elements I think you should get from wading through that presentation:

  1. A generator can return any kind of Python object. That is, it isn't limited to returning the numbers of a sequence. If you paid close attention to my Pythonic Python from July, 2013, you may remember that one of the points I made there was that Python functions can return large complex objects, not limited to just a number or just a pointer. Better still, Python takes care of the book keeping to automatically garbage collect the returned object if you are no longer using it.

    Beazley has examples with a generator returning strings (lines from log files), and then takes an unexpected turn to have the generator parse the strings into values and stash the values into a dictionary with a name for each value and then return the resulting dictionary as the generator's output. (A dictionary per line of the log file!) My initial reaction to that was to be horrified at the overhead, but if you think about it, looking up a name in a dictionary is quite central to Python's run time modus operandi, so dictionary objects being generated is perhaps more general than generating some more specific Python class object, and looking up values by name is pretty much the same as using a name of a member of a class object to get to a value in the class object. So given that Python is able to get decent performance from run-time interpretive execution, generating dictionaries is a lot more sensible then my initial gut reaction took it to be.

  2. A generator is just Python software so it can do anything that any Python software might want to do to provide the next value in the sequence. It can compute the next value using a formula, or it could access a file to learn the next value. It is even able to make use of another generator to get an input sequence that it manipulates and passes along. So generators can be chained together into long pipelines.
  3. If your program is basically about iterative processing of a series of stuff, then chaining together pipelines of generators can fundamentally shape a clean structure for your program and with a little practice you'll soon have a collection of useful reusable filters that you can use to construct future programs that you haven't even thought of yet. Share them with your friends. If you own the code, consider making it (and it's documentation) GPL licensed and freely shared on Github or some other such public place.
I'm seeing hints on the Internet that future Python releases will have even more use of generators. e.g. standard approaches built in to the language to process streams of events. e.g. Brett Cannon's 40 minute talk: "Python 3.3: Trust me, it is better than 2.7". He foreshadows a Guido Van Rossum talk about Python 3.4 scheduled for that same conference. If you can find a link to a video of Guido's talk about 3.4 and new roles for generators, please share it in the comments section here.

Saturday, November 30, 2013

Linus Torvalds on Teaching Children to Program


Linus Torvalds in this less than 3 minute video clip gives a great answer to a question about teaching children how to write computer code. He specifically mentions the Raspberry Pi as having the attractive property of being cheap enough to throw away. I've said before that if you persuade kids to try a computer programming course, some number of them will hate it, and will vow never to wrestle with computer software again. But there should be some who will decide this is fascinating and will pursue it further, perhaps making a career out of it.


http://www.youtube.com/watch?v=2KfJiWR1FPw


My conclusion is that an introductory programming course should therefore be short. I like Udacity CS101. It is nominally only 8 weeks at 5 hours of class time per week. It is self-paced and not on a fixed schedule. You may want to see my blog post: Is the Udacity CS101 Course Watered Down?


There are many possible ways to introduce computer programming. For example, you could pick a commercially important programming language, e.g. C or Java, and organize a course around learning that language. Or you could create/select a student language just for the students to get started with the concepts (Scratch, Logo, Basic, CUPL, ...) and teach that. I think Udacity CS101 chose wisely in picking a subset of Python. Python is a clean, powerful, multi-paradigm programming language that does see some real use commercially. Udacity CS101 doesn't visit all aspects of the language, but it does teach enough of it to give a good start at understanding the construction of computer programs. I believe it is much easier to get started in Python than in C or Java and that Python can carry you a lot further than Scratch, Basic or CUPL.


Another approach to introducing computer programming is to pick projects that are particularly attractive to students. Robots and computer games are two oft-mentioned examples. The parts and tools needed for a Robot-centered course call for a substantial investment ($10-$25 thousand per team is a working estimate I've seen on the web) and also requires comparatively large secure space to store the project, parts and tools. Real-time software that interacts with sensors and motors strikes me as more advanced material then a short introductory course should aim to cover. Games keep the work in the virtual world, so there's less need for parts and a workshop space, but interactive software with graphics is again, in my opinion, more advanced material that a short introductory course should aim to cover. Fair enough to stir into an introductory course a bit of foreshadowing to hint at how the material the course is covering can be extended to work in games or robots.


But I haven't any real experience teaching computer programming to students. I've been trying to launch such a course at the local community center here in the New Cassel section of North Hempstead, NY for well more than a year now, but it hasn't gotten off the ground yet. A shameless plug for yet another of my blog posts: Marketing the Importance of Programming Education. The comment thread on that article is, in my opinion, particularly worth reading.


A reminder: Blog sites such as this one are intended to be 2-way communication, not just reading material. Whether you are a student, teacher, programmer, experienced or inexperienced, you are invited to post comments about this article down below. Suggestions, counter-examples, criticism, pointers to other sites that said it better, and, of course, praise are all welcomed. Anything but spam.

Saturday, September 14, 2013

Bicycles for the mind... A Steve Jobs talk from long ago.

1980

In the Introduction talk to Udacity CS101, Professor Evans mentions Steve Jobs having compared computers to "bicycles for the mind".
I think I've now stumbled across the talk where Jobs more or less said that. Run time for the Jobs talk is about 20 minutes. The bicycle reference is around the 6 minute mark in the Jobs video. Evans attributed the quote to circa 1990, but the talk is said to be from 1980, and given Steve's youthful appearance in the video, I believe the 1980 date.


Speaking of small errors, one of the annoying things in Jobs talk is he speaks of meeting with some 4th and 5th graders, but he then calls them 4-5 year-olds. I think 9-11 year-olds would be a lot closer to correct. 20 kids and 6 Apple computers? What a depressing student/machine ratio that would be these days!


Jobs mentions Visicalc in his talk like that is something that everybody in the audience knows of. But here we are some 30+ years later and I'm no longer sure that you all know what Visicalc was. Happily, Wikipedia remembers. Even if you remember Visicalc, I recommend that you visit the Wikipedia page. It has some wonderful interesting links, including one that lets you download a free copy of Visicalc for your x86 Windows PC. That version was written for DOS 1.0 so it only works within the current directory. DOS 1.0 didn't have directories, just disk drives. Most folks back then didn't have disks with any more capacity than a 5.25" floppy disk. In 1980, that would have maybe been 140KB of storage space.


One other link to particularly take note of is the one that asks "What if Visicalc had been patented?". If you haven't been paying attention to the arguments about software patents and why they are not good for the economy, you really should Google up some background reading for yourself, maybe sit through a Richard Stallman talk or 2 about "intellectual property". Be forewarned that Stallman's talk is a 2 hour talk, so take a bathroom break and get yourself a fresh mug of coffee, tea, or whatever before you fire up the Stallman talk.


If I'm going to mention Steve Jobs and Richard Stallman in the same blog post, it is probably appropriate for me to point also you to this short video where Stallman contrasts his own accomplishments vs. those of Jobs and of Bill Gates.

Time marches on, but progress?

Listening to Jobs 1980 predictions for what the heck we'd do with even more computing power, I can't help but be disappointed with how little real progress we've made on that front. The computing power has, of course, materialized as predicted, and I suppose the graphical user interfaces of Windows, MacOS and web browsers is something of a usability improvement compared to DOS 1.0, but I was sending e-mail and posting netnews items aplenty back in 1980 and it isn't like that process is hugely different today. To keep things in perspective, the Macintosh computer was introduced in 1984. Here's an early 1984 video of Steve Jobs giving a timeline leading up to the Macintosh. It's only about 7 minutes long and includes the famous "1984" teaser ad for the Macintosh; an ad still worth watching, in my opinion. Here's a 10 minute video of Steve Jobs actually introducing and demonstrating the Macintosh.


Still, if you have a problem that you want to solve with a computer, are the barriers to solving your problem significantly lower today or about the same despite the powerful GUI computers that are now available today? If there's an existing product that fits your needs ("there's an app for that"), your path is easy, but if you really need custom software, perhaps a custom database, I expect you still have a rough road ahead. "Cobol is to Visicalc as Y is to Z", but what are Y and Z?


Comparing the Python language to the programming languages of 1980 (C, PL/I, Cobol, Fortran) I guess there's some evidence of our having learned to apply plentiful compute power to making the programming job a little easier, but there's still a steep hill to climb to bring computers to bear on your problem, whatever your problem might be. The Internet, the World Wide Web and search engines seems to be the most evident signs of progress in the computing world since 1980. I do wish the world had more progress to show on reducing the barriers to applying computers to solve problems given the passage of 30+ years since that Jobs talk. Are there specific improvements in the computing world that I'm overlooking here and not giving proper credit to? Should smartphones get mention or are they just scaled down screens with battery powered small computers.


If I was better at HTML, maybe I could rig this article to provide background music as you read the previous paragraph. Or am I being too sentimental about lack of technological progress?


If you are completely unfamiliar with Stallman's contributions to the notions of "free software", you might give a quick read of a past blog post of my own as a way to get started at understanding software licensing and Stallman's GPL in particular: See "Copied Code or Unfortunate Coincidence".

06/11/2014 - Updated: The Steve Jobs talk link went bad! Why didn't anyone tell me with a comment so I'd know? Anyhow, I found a link that works (today).

Wednesday, August 28, 2013

Learn How to Program Computers!

Say What?

News photo of an experimental self-driving Volvo from Engadget report.


Computer procesors show up almost everywhere these days. Desktops, laptops, cell phones, processors embedded in cars, processors embedded in printers, embedded in cameras, embedded in dish-washers.


One thing that they all have in common is that someone (or some team of folks) had to develop a set of instructions to guide the computer to do whatever it is that it does. Those instructions are called programs, software, and the stuff that goes into a program is called "code", not to be confused with "secret codes", though there is a connection if cryptography is what interests you.


So, no matter what, you are pretty much fated to be a user of computer programs, but with some effort on your part, you can learn to write your own computer programs too. Creating a computer program is called "software development". You can learn to do software development on your own. I'll caution up front that seriously big projects generally are tackled by teams, not individuals working solo. But the longest journey starts with but a single step.


My intent here is to convince you that you should embark on the long journey of learning to program computers, to do software development.

Motive

There are plenty of reasons why you should learn how to program computers. Before you begin on that path, you might want to think about what your motive is. Are you hoping to write your own computer games? Want to understand Cyberwarfare before you are noted as a threat by Skynet? Interested in autonomous robots? Self-driving cars? Want to develop a fancy web site of your own? Thinking it might be a useful skill when seeking a serious job? Want to understand how the NSA accidentally intercepted calls from Washington, DC, when they meant to intercept calls from Egypt?


I can't tell you what motivates you. I will caution that this is no short trip, so you should probably be sure you are well motivated before you dive in.


I'll also mention up front that the early days of getting started with developing your own software can be frustrating. As you master the basics, a self-driving car may seem awfully far away. Part of my hope here is that I can convince you that if you keep your motive in mind, you can work through the steep initial learning curve.

Age restrictions?

In my opinion, there's no upper bound on the age when you can learn to program computers. If you are past retirement age, that might alter your own list of motives for learning, but it is no reason to refuse to give it a try.


Can you be too young to learn to program? Well, programming does generally involve reading and writing, so if you haven't gotten proficient at those skills yet, you may find it hard to get into software development. But then, how is it that you are reading this article? The US apparently has regulations that strongly discourage web sites from registering information for children under age 13, so if you are under age 13, it is important that you discuss your plans with your parent or guardian and have permission from them to get involved in online courses.

Cost?

If you have access to a computer with a good Internet connection, you probably have all that you need to get started. If you don't, then how is it that you are reading this article?


Of course, if you have money to invest in this project of yours, there are things you might want to look into. For instance, books. You can get plenty of materials for free here on the Internet, but sometimes it can be useful to have a paper document that you can bookmark, dog-ear, highlight and annotate. Don't feel you have to invest in books up front, but if you can find a good local book store, you may find that there are useful things to be found by browsing. Your local library may also be useful, though in my experience, the local library tends to be woefully short of current technical books. The good news is that if you can find titles worth looking at, perhaps from web searches of places like amazon.com, then most likely your local library can arrange an inter-library loan so you can examine the book without having to buy it first.


Of course, library books, including books borrowed on inter-library loans, need to be treated politely, not dog-eared, high-lighted and given marginal annotations. And they do have to be returned after a relatively short time. If you find a title that looks really well matched to your needs, that's where you just might blow your allowance on an order from an online book-seller, so you'll have a copy of it for your own. Amazon.com does have provisions for wish lists, sort of like bridal registries, so as you publically grow your list of titles you hunger for, you'll at least make it easy for folks thinking about getting you a birthday present or Christmas present.


Libraries can also be a great place for getting free public access to Internet-connected computers. You might find that there are administrative obstacles to your installing software development tools on the library's PC's, or even filters to protect you from the educational materials. Don't let those barriers stop you. Talk to the librarian to find out who is in charge of those kinds of filters. Most likely, arrangements can be made for good reasons like you have.

Courses?

There are many computer programming courses available on the Internet for free. "Massive Open Online Courses", MOOC's, featuring different programming languages and different levels of material. Some aim to serve particularly younger students. You might look, for example, for courses that introduce the "Scratch" programming language.


I haven't taken a "Scratch" course myself, so I'm not going to single out a specific suggestion here. Just try a simple Google search for:


    scratch programming course


and let us know in a comment which course you picked and why, and how that went for you.


But if you feel you are ready to learn a somewhat more conventional programming language, one that will take you further than I believe Scratch will, my suggestion is CS101 from Udacity.com, where you will learn to program using the Python 2 programming language.


The Python programming language continues to evolve. There are Python 3 versions available today. The world is still catching up to that. You'll be fine starting with Python 2, and learning the differences later on to get over to the newer versions. It is important that you know that there are multiple versions and that when you are shopping for books or tools that you get a version that matches what the course is expecting you to have.


There are other courses available, though I haven't tried the others myself. Certainly there are courses that teach Python specifically for game development. And there are plenty of courses that teach other languages, Java and C, for example. But in my opinion, CS101 from Udacity.com is a good place to start. It is free, self-paced, you work on it on your own schedule. Nominally, it is an 8-week course. It doesn't have pre-requisite other courses. I believe it is an excellent place to get started with MOOC's. There's a final exam at the end and when you pass it, they will e-mail to you a certificate to commemorate your accomplishment. There are reports on the web of real colleges that even give credits if you are a registered student and pass the Udacity.com CS101 course, but being a registered student at a physical college is outside the realm of stuff you can try for no charge.


If nothing else, trying a MOOC to get started will show you if this is a field that holds your interest. I know software development has been a long standing interest of my own, but I also know that some fraction of the students who try it find that they absolutely hate programming. If you find that's the case for you, my advice is that you tough it out to completion of the introductory course and then look for other fields that do hold your interest. It's only a couple of months to work through Udacity CS101, and it isn't anything like a full-time course load while you are working through just the introductory course. Getting the certificate isn't good motive to start the course, but perhaps it is a good motive to stick it out to the end.

Where to find more?

code.org is a web site that advocates that everyone should learn how to code. They offer 3 editions of a promotional video to promote interest in the field. One is a 1-minute teaser. Another is a 5-minute edition featured on their web site's front page. And if you have 10-minutes to spare, there is a full edition available.


There are links on the code.org site to various local places to learn to program. For example, there's a brief plug there for the "Yes We Can Community Center" here in Westbury, NY.


Details of the schedule are not yet nailed down for Fall 2013, but if you are local to here, one way to take on CS101 is to sign up with the Community Center. The Center has the computers and Internet access, and it will have other students so you won't feel too much that you are on-your-own. And, for what it worth, I'll be available to answer questions and help keep you motivated while you are working through the course online.


Not quite free, as there is a membership fee to sign up with the Community Center. But use of the basketball courts, game room and locker room and access to quiet study space for your homework time all come with that membership, so it's probably worth joining if this is your community. (Use of the fitness center is not included in basic membership. Sorry).


The schedule I've proposed is that Monday evenings we'd meet as a class to share discussion of progress and problems. Other school nights I'd be available to answer questions 7-9PM or by appointment.


In any case, you can try udacity.com CS101 on your own before we even get started and then continue at the Community center once we get our act together there. Please, do let them know at the front desk that you're interested in taking CS101 as seating is limited.

Free for Senior Citizens

If you are a resident of North Hempstead and are age 60 or more, you are eligible for free membership in Project Independence and get a free community center membership too when you join Project Independence. Such a deal!

Further reading

Benefits of Teaching Kids To Code That No One Is Talking About - This blog post by an online acquaintance of mine has an example of a Scratch program, and a link to a video of a talk by the creator of Scratch.


Is Udacity CS101 Watered Down - This is a blog post from me in December 2012, describing what you should expect to get out of the online Udacity CS101 course.


Where to Get Python - This is another blog post from me. This one describes how you can install Python on your own PC. Note that back when I wrote that, Udacity was still using Python 2.6, but the course has since updated it's software to Python 2.7. From an end-user point of view that's an almost imperceptible change.


There are numerous Youtube videos available about learning to program games. Here is Episode 1 of a series that is dozens of videos long. Part 1 shows off a couple of games the guy has written in Python and describes what prerequisite knowledge he expects you to have to get started with his tutorials.


This isn't the first time that I've written about plans for CS101 at the Community Center. For more details of my intended format for the weekly meetings, see my blog article: Marketing the Importance of Programming Education

Thursday, August 22, 2013

What's the fuss about parallel programming?

What's the fuss about parallel programming?

A young friend of mine, now a 2nd year computer engineering student, asked me:

What is parallel programming? Why is parallel programming regarded as important in the future?

I don't have any idea about parallel programming and try to learn  by Googling. Yet,  it is difficult to understand. Why mutable data has been considered as inefficient in programming recently? How it creates problem and in what way functional programming avoids this mess? Will functional programming increase the performance of multicore systems?
Also, to which OS books should I refer? As I am starting my study on my own, and I want to get good at OS and basically able to understand the difference between linux and windows, which book should I follow? Earlier, you said that you are interested in operating systems and also best at it. Please, just suggest me some books which would able to justify the differences between linux and windows technically.
In which language is OS programming done?

Image of multiple processors taken somewhat out of context with a thank-you to Tom's Hardware, a web site where people try to keep up with this stuff


This is my reply to that e-mail...
You ask "What is parallel programming?"   That's a very similar topic to another topic you recently asked about:   concurrent programming.   Both concern how to write programs that do more than one thing at once so that overall performance is improved.   e.g. if the time to run the program depends on "n" (perhaps n is the amount of input data to be processed), then what a parallel program wants to do is apply more than one processor to the problem so the job can be completed sooner than one processor would be able to.

For example, if the job is to sort n items, you might divide the list up into a separate list per processor so each processor needs only sort a shorter list of items.   Of course, before the job is finished, the multiple shorter lists need to be merged together to make the final result.

Distributing the items across the processors is work, merging the lists back together again is work.   Whether the overhead of those extra steps is worth it or not depends on things like how much memory each of the processors has good access to.   If the items divided make a small enough list to fit in the RAM of each processor, then things are probably going to go very fast.    But if the sub-problems are still big enough that you need to spill things out to intermediate work files, and if the extra processors don't have good access to the disk space used to store the spill files, then the dividing up of things might turn out to be a net loss in performance.

http://en.wikipedia.org/wiki/Parallel_programming_model

Moore's Law

You also ask "Why is parallel programming regarded as important for the future?".   Well, if you go way back to the early days of integrated circuits, Gordon Moore predicted in 1965 that the number of transistors on an integrated circuit would double every 2 years.   He thought that observation would hold true for 10 more years or so.   We actually have gotten through a lot more doublings than that and aren't done yet (though folks are starting to fret that they can see ultimate limits ahead - so it won't go on forever).
His prediction was more and more transistors and it isn't entirely obvious that that translates to mean faster computers.   But, in fact, what folks have done with those transistors is figure out ways to apply them to make faster computers.    If you look back to the earliest IBM PC's, the processor chip didn't even do floating point arithmetic.   If you needed faster floating point, you'd have to add a math co-processor onto the motherboard (there was a socket for that additional chip).

I confess to liking that idea of having separate useful pieces that you can custom integrate to create a tailored computer with exactly the strengths that you want.   Alas, the expense of having multiple chips connected together at the circuit board level argues powerfully against that piece-part model of the chip business.   The trend instead has been to absorb more and more functionality into a single chip - whole systems on a chip - just to be rid of the sockets and pins and propagation delays of getting off-chip and on-chip and back again.

So where did all the transistors get spent to speed things up?   Some of it is obvious.   Computers today have amounts of memory that were unthinkable just a few years ago.   Along with more memory, you certainly have more cache and more layers of cache to speed up access to that memory.   There's much to be learned in contemplating why there are more layers of cache instead of just bigger cache.   But that's a more hardware-centric topic than I'm comfortable explaining here as a software guy.

Besides more memory and more registers, the paths and registers have gotten wider.   Where there were 8 bits in the beginning, there are often 64 bits today.    You can try cranking that up in the future to 128 bits, but at some point you get into diminishing returns.   Slinging around 128-bit pointers in a program that could be happy dealing with only 32-bit pointers may not be optimal.    Maybe the problem is just that we need a little more time for programs to comfortably exploit gigantic memory spaces.   My PC today only has 2GB of real RAM.    32 bits is more than enough to directly address that much memory.  2^32 in fact is enough to directly address 4GB of RAM.   So the line of needing more than 32 bits isn't super far away. But 64 bits is enough to directly address 16 exabytes of RAM.   I can't even afford a Terabyte of RAM yet, so needing more than 64-bits is surely a long way away. (1 Terabyte=1024 Gigabytes. 1  Petabyte=1024 Terabytes.   And 1 Exabyte=1024 Petabytes).

http://highscalability.com/blog/2012/9/11/how-big-is-a-petabyte-exabyte-zettabyte-or-a-yottabyte.html

Those are really big numbers.   Bigger than even Doc Brown is likely ready to contemplate:

http://www.youtube.com/watch?v=I5cYgRnfFDA

But it isn't always obvious how best to spend the many transistors that the progress predicted by Moore has provided to us.   I see a certain amount of oscillation in design approaches as things get wide and then get back to serial again.   Look at ATA vs. SATA, for example.

http://en.wikipedia.org/wiki/Serial_ATA

One way to spend transistors is to make more complex circuitry to make the time for each instruction be shorter - do faster multiplication or division, but there's only so far that you can push things in that direction. Current consensus seems to be that making faster and faster processors is getting to be very difficult.   As clock speeds go up, the chip's thirst for electrical power goes up too and with that the amount of heat that has to be taken away from the chip to avoid reducing it to a puddle or a puff of smoke.   So, the industry's current direction is toward spending the transistors on having more processors with moderate speed per processor.   The aggregate instruction rate of such an array of processors multiplies out to nice high numbers of instructions per second, but the challenge is how to effectively apply all those processors to solve a problem faster than an older uniprocessor computer would be able to. Hence the anticipated growing importance of parallel computing in the future.

I think so far I've answered the questions in your subject line.   I hope you have the patience for me to try answering the questions in the body of your mail too.

A Day at the Races

I see your next question is "Why the fuss about mutable data?"   Well, as I understand it, the concern is that if your data is mutable, you need to worry about inter-processor synchronization and locking so that when a processor updates a stored value, that it doesn't interfere with some other processor.
The processing of read-only (immutable) data doesn't have to worry about locking and synchronization.  But consider something as simple as A=A+1, where A is a mutable value.    Underneath it all, your processor needs to figure out where the value of A is stored, fetch the value into some arithmetic register, add 1 to the value and store the value back into the location for A.   If A is accessible only to your one processor, there's little to sweat about, but if A is accessible to multiple processors there's a potential for a race.   What if both processors have fetched the value of A and both have incremented their copy.    Only one of them has the right answer.   If they both store their new values for A back to the shared location, the final result is one less than it ought to be.

One solution is to have specialized hardware that makes the A=A+1 operation be atomic, indivisible, so there's no chance of one processor seeing the old value when it should be using a new value.

There's the challenge of figuring out exactly which atomic instructions are most useful additions to your instruction set design.   IBM mainframes had an interesting, though complicated instruction called compare and swap.   As I remember it, the instruction took 2 registers and a memory location.   If the first register matched the value in the memory location, then the 2nd register would be stored into the memory location.   If they didn't match, then the memory location would be loaded into the 1st register. And the whole operation was indivisible.    So a processor could do it without having to worry about whether some other processor was operating on the same memory location.   So, you could use compare and swap to do our A=A+1 operation safely.   You fetch the value of A into a register. You copy that register to a 2nd register.   Add 1 to the 2nd register.    Now do a compare-and swap to store the result back to memory.   If the compare and swap sets the condition code that says the 1st register didn't match, then sorry, but you have to repeat your computation.   Copy the newer value from the first register to the 2nd register. Add 1 to the (new) value to get a newer value and try the compare and swap again.   Of course, if there are many processors in hot contention for the value of A, then you might have to spin for a while in that loop trying to compute the right value and get it back before it becomes stale.

The compare-and-swap instruction can be used for more than A=A+1 kinds of computations.    For instance consider a linked list of items, perhaps the run-able thread list in your operating system kernel.   You want to be able to remove an item from that list.   That involves fetching the link to the next item, fetching the link to the item after that and then storing the link to the next next item into the location where the link to the item you are removing from the list came from.

    A  ----> B ----> C becomes A ----> C

As with the A=A+1 case, there's the potential for a race if there are multiple processors that are contending to pick B off the list.  compare-and-swap can at least make it safe from races, but again, if there is hot contention among many processors, there can be much wasted spinning before a processor succeeds in grabbing B off the list.

So, if you have careful control at the machine instruction level, the problem is practically solved.   But that sort of implies that you drop down into assembler language from time to time or you have a compiler that generates incredibly clever object code that knows where to use these specialized multi-processing instructions.   What if you are using a garbage-collected language like Java or Python?   Maybe your problem is worse than the value of A that you used in your computation became stale between your fetch and your store back to memory.   Maybe the location of A has changed entirely and your store operation is smashing something else entirely different than the variable A.   Big trouble ahead...   In fact, if you think in terms of Python, maybe by the time you are trying to store the new value, A isn't even an integer any more. "Gee, it was an integer value when I fetched it.   Who the heck changed it to be a floating point number in the meanwhile?".   Could be subtler: Python will happily and silently promote a int to a long if the value gets too big to fit into an int, so you need to be very careful that the value you fetched still makes sense before you store the result back to memory.

The article I pointed you to the other day "Downfall of Imperative Programming” asserts that "Imperative programs will always be vulnerable to race conditions because they have mutable variables".   So functional programming languages, by avoiding mutable variables, dodge a major bullet in the multiprocessing world. The thing that I don't know is how to be sufficiently productive in functional programming languages for Haskell to be worth the trouble to learn.   The Downfall article predicts that the race conditions are an insoluble problem for imperative programming language implementations.  I'll happily accept that there's trouble ahead to watch out for, but I do have a bit of difficulty accepting that the races absolutely can't be resolved.

Python's Global Interpreter Lock

Python worries about the possibility of races among threads in interpreting the instructions of Python code. They have a "Global Interpreter Lock" (GIL) to assure that one interpreter thread won't change a value in use by another interpreter thread. Folks worry that this coarse level of locking will keep Python programs from being able to scale up with increasing numbers of processors.
I've seen some clever dodges of the GIL in Python programs, mainly by spreading the program across separate address spaces (multiple Python interpreters, each with their own GIL) and limiting interprocess interaction to some carefully controlled set of places in the code with appropriate locking protections.  On the one hand, this doesn't give transparent scaling up from a uniprocessor to M processors all running in parallel, but on the other hand, it does get the job done.

My (weak) excuse for not having more first hand experience with this...

My home PC doesn't bring multiprocessors to the party.   Some day I hope to replace it with an i5-ish based computer with 64-bit addressing and >4GB of memory.   As a retiree with a rather modest pension, that's a discretionary expense that I've been postponing into the future.  Maybe in the meanwhile my target will shift to something with way more processors than an i5.   What I have in mind is something with enough oomph to be able to run Linux and Windows both in virtual machines (Based on Xen, VMWare, something else?  I don't know...). Heck, Microsoft isn't even making it easy to buy such a configuration without paying for a Windows license twice (once bundled into the PC's base price and then again for an installable copy that can be installed into a VM).  I'm assuming that a re-install CD that wants to reload Windows onto a bare PC isn't going to be able to install into a VM environment.   I'm expecting that multi-processor race conditions and their associated problems will come along naturally to my world once I have a rich enough configuration and that encountering those problems on more than just paper will motivate me into doing something about them.
Maybe I'm just old-fashioned in thinking that what I need is a richer computing environment here at home.   Maybe the right thing to do is to venture out into things like Amazon's Cloud Computing service and see what kind of trouble I can get into using other people's multi-processors via the Internet.  One of my worries about that, is maybe the underlying MP nature of their cloud services is too deeply wrapped for me to really see the problems I'd be up against from MP.   And, "look, dear, here's the marvelous new computer I just bought" is a much easier conversation to anticipate having with my wife then "Just let me pay this bill for cloud services.   It isn't so much money and I did really learn from having tried their services."

Comparative Operating Systems

You ask me to recommend an OS book to better understand Windows vs. Linux.  I don't know which book is the right choice.    Certainly an Amazon or Google search will turn up a large number of candidate titles. Perhaps your school's library has some of those titles so you can look them over, or perhaps they can arrange inter-library loans for you to be able to look over some of the candidate titles.   "Which of these is best" is always a tricky question because the answer depends so much on your particular criteria for "best"
So let me turn this around and ask you for a summary of your findings from digging into the too-long list of candidate titles and your recommendation.   You might want to ask your question of your school's professor for the OS classes too.   Maybe he's got a more formed opinion on this topic than I have.

Linux Weekly News

Meanwhile, I stand by my suggestion that you should make an effort to keep up with lwn.net  (free of charge at the price of having to lag back a week from the most current articles) to see what is going on in the Linux world.  Don't feel obligated to have the newest and most experimental kernel on your home PC,  But if you spend some time watching the evolution and planning of kernels, you'll have a better idea of Linux's strengths and weaknesses and what "they" are doing about the weaknesses.  Unlike Windows, if you are sufficiently motivated to want Linux to be different then it is today, you can make that happen.

Kernel programming languages?

What programming languages show up in OS programming?  Well, at this time, I expect the correct answer to that is C.  Other languages (e.g.Java and Python) do show up in supporting roles, but generally don't make it into kernel code.   Even C++ tends to need too demanding an environment to be a good candidate for kernel code.   Maybe as time goes on the kernel will sprout suitable layers of capability to make higher level languages more attractive for implementing functionality within the kernel but right now if someone tells you a kernel is written in C++, ask them more questions to confirm that.   It wasn't all that long ago that the likely choice for programming an OS kernel was surely assembler language.  Unix introduced the C language and the then radical idea of using a higher level language in the kernel and even having kernel code that is somewhat portable across computing system architectures. (To calm the historians in the audience, I'll concede here that I may be under-crediting the Multics operating system, portions of which were written in PL/I. And the Multics site gives credit to Burroughs for having done a kernel in Algol, but that's way before even my time).
Stack overflow article on the languages of the Android OS:

http://stackoverflow.com/questions/12544360/on-what-programming-language-is-android-os-and-its-kernel-written

Stack overflow article on the languages of MacOS, Windows and Linux:

http://stackoverflow.com/questions/580292/what-languages-are-windows-mac-os-x-and-linux-written-in

Not every answer is to be trusted to be correct on stackoverflow....

One sub-link of that article that I followed and that does look interesting and credible:

http://www.lextrait.com/vincent/implementations.html

lwn.net article on what's new in the Linux 3.11 kernel expected to become available in September 2013...
http://lwn.net/Articles/558940/
This is a particularly interesting link from one of the many comments on that lwn.net article about 3.11:
http://www.softpanorama.org/People/Torvalds/Finland_period/xenix_microsoft_shortlived_love_affair_with_unix.shtml

In Closing...

You quote me as saying that I'm best at operating systems.   I tried rummaging in old mail to you to put that statement in context, but didn't succeed in tracking down what I said.   I will concede that I'm especially interested in operating systems, and given a list of computer science topics, I'm probably more interested in operating system then in most of the others, but claiming I'm best in operating systems sounds like it surely needs some context.


I confess that except for command line pipelines, I've never actually written a multi-threaded program of my own. So don't assume more expertise here than I actually have.

Sunday, July 28, 2013

Pythonic Python - Writing Python code that fits the language's idioms.

A recent posting by +Luke Plant to the Google+ Python community about the importance of PEP-8 reminded me that for quite a while now I've been thinking I should compose a blog posting about idiomatic Python code - and that's what led to this article.

Now I know this is a very small candle trying to light a very large dark space, but so it goes. My own Python experience has so far been limited to small projects and class-work, no larger scale production quality team efforts. The good news is that that limitation in my own experience means there's plenty of room for you to chime in with opinions of your own on this matter. I write posts to my blog in hopes of sparking up some conversations. Do feel free to speak up!

Some Orientation if you're New Around Python

If you are new around Python and aren't entirely clear on what it means when we talk about "the Python community", I offer you this orientation section lest you be confused by technical details in my words here. If any of it remains unclear, do speak up about that and I'll try to expand the material to cover more.

A "PEP" is a "Python Enhancement proposal". There's a web site where all the PEP's are published and shared. PEP 0 is an index to the PEP's. PEP 1 is a guide to how to write and submit a PEP.

Most PEP's are proposals to enhance the Python programming language in some way.
e.g. PEP 435 proposes adding an enum data type to the Python standard library. It's been a long discussed topic. PEP 354 for example proposed something similar but was rejected in 2005. PEP 435 has been accepted and is scheduled to be implemented and released as a feature of Python 3.4.

Other "PEP's" are merely informational, not really enhancement proposals at all.
For example, PEP 429 is the nominal schedule and plans for the Python 3.4 release. So, if PEP's aren't always "Enhancement proposals", what are they? PEP's are public records of consensus opinions of the Python community. Not every voice counts the same. Benevolent Dictator for Life (BDFL) and Creator of the Python language in the first place, Guido Van Rossum, has extraordinary influence on the fate of a PEP. Fortunately, he generally shows good judgement in steering the language.

Among the informational PEP's, PEP-8 is a style guide for Python code. If you don't want your code to look strange to the eyes of experienced Python programmers, you should try to comply with the guidance of PEP-8. To help you do that, there's a PEP-8 checking program. Actually, if you do a Google search, you'll find that there's more than one such PEP-8 checking program available. You should have at least one of these programs in your tool box and make a habit of running it against your code and spending the time to tidy things up to make the checker program happy.

It's not that you can't ever bend the rules, but you darn well better have an excellent reason why deviating from the style guidelines was worthwhile in the exceptional case that you decided not to fix.

Another informational PEP that you should read is PEP-20, the Zen of Python. Unlike PEP-8, the guidance of PEP-20 isn't something so simple that a straight-forward program can look at your code and say whether or not you were thinking like a Python programmer when you wrote your code. PEP-20 does try to get your head into the right way of looking at the things that you wish to program using Python.

Beyond Style

There's more to writing "Pythonic" Python code than following PEP-8's style guidelines and letting PEP-20 shape your thinking. For example, given a collection of things (a "list" being the most typical way of setting that up in a Python program, if your reflex to process that list is to think "DO I=1 TO N"... then you are probably still under the influence of Fortran or C or some other such old programming language. A more Pythonic way is "FOR ITEM IN LIST:"... Now there are lots of special situations that might drive you to explicitly stepping an index through a list, even in Python, but don't do it as a simple automatic habit. Ned Batchelder has written an excellent tutorial on how to "loop like a native".

One other area where I've found I have to fight against habits formed in working in other older programming languages is in conceiving of the types of return values from a function. In some old languages, the return values were limited to something simple, and to exactly one thing. But Python is entirely dynamic, so you can feel free to inexpensively return elaborate data structures or even multiple values (tuples) at a time. It isn't inordinately expensive because the implementation doesn't copy the values around, just pass descriptors of the values. The language's runtime garbage collector takes care of reclaiming the storage space when you no longer need the fancy value that you constructed.

Additional Tools

It is important to understand that Python does incredibly little error checking at "compile" time. Your code will pass without complaint from the Python language processor, even if your program has grossly mis-spelled variable names or calls non-existent functions. You won't hear about the errors in a given line of code until you actually try to execute that line. This makes testing your code incredibly important. You should definitely look into Python unit-test tools so you can embed test cases with your code and be well prepared to routinely re-test after you make revisions to the code. Related to testing, you might also benefit from coverage tools that report which portions of your code remain unexercised. This may guide you into beefing up your unit test cases. Sadly, even 100% test coverage of all the lines of code still can't guarantee that your code has no undiscovered bugs lurking in it. But if you haven't even exercised all the lines of code it is easy to anticipate that there may be easy-to-find errors lying in wait to spring out at you at some inopportune time.

There's no real substitute for good judgement and as the old adage explains good judgement is something you learn from experience and experience is often something you gain from applying bad judgement. Another tool that may draw your attention to places in need of better judgement is sloccount. sloccount tells you how many lines of non-blank, non-comment source code you've written and while it is counting, it computes complexity metrics for your functions. A function that is oversized or that scores as exceptionally complex deserves to be re-considered. More often than not, those are the kinds of functions where your undiscovered bugs are lurking.

There are multiple static checking programs that try to find the more obvious kinds of problems for you. pylint, pyflakes, and pychecker to start you off with 3 names to Google search for. Some of the suggestions from these tools can be very annoying, like if I need a short-lived integer variable for local use, why shouldn't I name that variable "i"? But generally the checkers are tunable to tailor the rules to your taste. Don't just get annoyed with what the checker program tells you. Look at what it thinks it sees and see if you could do better and make it happy while you are at it.

Data Types.

One other aspect of the Python language that you should pay attention to is it's richness in data types. strings, lists, dictionaries, sets, tuples... And those are just "collections" of values. If you find yourself frequently searching through a list, stop and think whether a list is really the right choice. Maybe you really ought to use a dictionary to make it simpler to check if a given value is in the collection.

Modules and Name Spaces

If your Python programs all tend to each live in exactly one file, then odds are you aren't making use of Python's modules and name space capabilities to separate your code into manageable sized pieces. Ultimately, that will limit you in your ability to tackle larger projects such as multiple-person programming teams. Keep an eye out for possible reusable modules that are worth separating from the specific problem at hand so you can use the same code elsewhere in the future. Python is quite liberal in its handling of type ("duck typing"). You can exploit that to make your code quite flexible about what data it is willing to deal with. Take the time to carefully document what the requirements are for the data that your module can handle. e.g. maybe you had in mind that it would handle "employees", but perhaps it could be equally happy with any kind of object that has a mailing address as part of it ("customers" for instance).

Multiple paradigms.

Although Python is not a gigantic language with the sort of sprawl that PL/I was notorious for, Python does allow for more than one programming style. It certainly has support for object oriented programming as well as structured programming. Happily, it doesn't insist that you make use of all of its possibilities, but if you have been shying away from some aspect of the language because it supports a style that you are unaccustomed to, do push yourself toward learning how to use that aspect of the language appropriately. "generators" are a kind of co-routine and you may not have run into such a control structure in other languages, but they are worth the time to learn. Object oriented programming is still a weak area for me, but I've been working on trying to understand how to put that to good use. Test driven development is new to me too, but again I've been trying to regroove my mind to pay attention to doing things that way.

Libraries and Frameworks

One of the mixed blessings of working in Python is that there are many rich libraries of existing code available for your use. Do plan to spend some time searching to find what is available that may be helpful to you. The code is generally free for you to download, but you may need to invest some time to understand it and bend it to your will. Forking it to make a specific-to-you version is probably a bad idea. But reinventing the wheel on your own is probably an even worse use of your time. If the library module isn't going to comfortably fit into your program, that may be nature's way of telling you to return to your favorite search engine to find another alternative implementation to use instead of your initial "find".

Learning the Python language is just a start. Learning to put it to good use is a much taller order. As Peter Norvig promises in his essay, "Yes, you can learn to program in only 10 years". But don't get discouraged. Learning new stuff every day can be great fun.

11/10/2013 - Corrected a typo. "are are". Being your own editor has its hazards.

Sunday, July 7, 2013

Recursion

One of the interesting computer science topics that Udacity CS101 introduces is "recursion". Recursion is where you define a function in terms that in some cases require the function to call itself. This is the main topic of Unit 6 of the course. There are important design considerations to be taken into account if you are going to use "recursion" in your implementation of a function.

  1. Base case(s) - It is crucial that your function have at least one combination of inputs that do not trigger yet another recursion. This non-recursive case is called the base case of your function. If you don't have at least one base case, then you are fairly certain to have an unending loop that never produces a final result.
  2. Progress - It is similarly crucial that your function make progress toward the base case(s) as it recurses. If you have situations where sometimes the function re-invokes itself with the same inputs and state as it had previously, then it may be more subtle, but almost surely you are stuck in an unending loop that never produces a final result.

Not every programming language supports recursion. Cobol and Fortran for example traditionally do not. Some languages (e.g. PL/I) support it, but only if you declare that a specific function may be invoked recursively. ("PROC OPTIONS(RECURSIVE)"). Python supports recursion without any need to declare your intent to use the capability, but Python's support of recursion does not include "tail recursion optimization". Tail recursion optimization is where a language processor recognizes the special case that a procedure is being called recursively, but that when the procedure returns to the point of the call, there's nothing more to do than to return to an earlier call to this procedure. A clever compiler can transform the code for such a program to do a plain loop instead of a recursive call. Alas, in Python, there's much that cannot be known for certain about the code until run time. Guido Von Rossum, the creator of Python and it's "Benevolent Dictator for Life" (BDFL) has blogged about why Python doesn't bother to try harder for this particular case. See: Tail Recursion Elimination.

A key fact to note is that if you've got code with a tail recursion in it, then it is reasonably straight forward for you to restructure that code to explicitly use a loop in place of the recursion. It apparently is in this fact that Guido draws enough comfort to not bother trying to optimize the handling of this kind of code.

Some folks look at the limitation of Python's support of recursion and wrongly conclude that recursion is a feature of the Python programming language that you should avoid. Ned Batchelder did a great job of de-bunking that assertion in his essay: Recursive Dogma.

There are lots of interesting discussions of recursion in the Udacity CS101 forum. Much of the debate is over whether or not recursion is something easy or hard to get your brain wrapped around. Some folks find recursion is an elegant way to express a function while others opine that iteration is a more natural way to conceive of a function's processing. My opinion in this debate is that even if recursion provides a straightforward clean design for a function, do think through how to transform that design into an iteration. Compare the readability, performance and limitations of the 2 alternative designs and pick the alternative that makes the most sense for your needs.