Currently showing entries with the tag: technology
|
page 1 of 1
|
Book Review: Programming Erlang
October 23, 2007 • 8:54PM • permalink
As you may know from reading my previous blog entries, I've recently been trying to mix up the books in my reading queue by exploring the benefits of a few new programming languages. Recently a friend of mine told me a few things about functional programming, concurrency and Erlang which inspired me to check it out.
Joe Armstrong, one of the creators of the Erlang language, has recently published a new book on the topic and its truly a fascinating read.
One of the biggest complaints I hear from other developers about any introductory level book about a new programming language is the lack of useful programs that can be created upon completion of the book. What I mean is that you may be able to do the normal "Hello World", Fibonacci sequence output, etc. - but you probably won't be able to do anything really useful. This isn't the case with Armstrong's book.
The main ideas of the book and of Erlang (free for most environments at http://www.erlang.org) in general is concurrency or the simultaneous execution of code. While C and its variants offer multi-threading, it is still essentially executing sequential code and hence subject to deadlocks, race-conditions, etc. Erlang enforces some strict rules from the get-go to support concurrency and allow for true simultaneous execution that is free from not only race-conditions and deadlocks, but from semaphores, mutexes and locks as well.
In order to do that, Erlang turns computer science on its head (from a sequential programming point-of-view) which Armstrong is quick to point out at every turn. For example, variables are only called as such because it makes things easier. The fact is they can't actually vary and an Exception is thrown if you even try.
On that same note, the equal sign is not the assignment operator like it usually is in programming, it is instead used to perform pattern matching. An example would probably work best to explain it:
1>X = 5.
5
2>X = 5.
5
3>X = 3.
=ERROR REPORT==== 16-Oct-2007::21:26:12 ===
Error in process <0.30.0> with exit value: {{badmatch,3},[{erl_eval,expr,3}]}
** exited: {{badmatch,3},[{erl_eval,expr,3}]} **
As I stated before, the = is not the assignment operator, it is instead used for pattern matching. An additional caveat though, when used with an uninitialized variable (which usually start with Capital letters), the variable is assigned that value. In line 1 above, we match the variable X against the literal value 5. Since X is uninitialized at the time we match it against the literal 5, it then takes on that value.
This is why, when we repeat the action in the second line, it returns the value 5 (indicating a match). Consequently, when we hit the third line, the shell throws an exception since we're matching X against 3, when it has already taken on the value 5.
You may wonder what the value of such an operator is, but when you dive into server programming, you'll see that it can be used (among other things) to direct functionality within network protocols. By matching against certain patterns, you can essentially code mini-conditional statements to perform various actions upon receipt of certain data. It seems complicated, but it's really not - since this is a Book Review and not an Introduction to Erlang, so I'll leave the explanation to Armstrong...
Within 75 pages, I had gained an enthusiasm for Erlang that was apparently infectious and it has been embraced by a few other developers in my Department (including Jon over at Rusty Razor Blade). While we're still not 100% sure it will be able to support the traffic load and perform fast enough, we're motivated enough to try. Armstrong makes it easy to learn from example too, since the book contains Erlang source to create a server for almost any major network protocol or project you could think of including IRC, SHOUTcast, a simple Error logger, a SQL Server and a Web Server.
We've discussed a plethora of different ideas we could run on our "new Erlang Framework", some more ambitious than others. We're convinced we could rewrite memcached in a few hundred lines of code, including all the features of the original - a few that are missing and commonly implemented in other cache systems - as well as a few of our own custom design. We figure if we can even get 80% of the throughput of our current memcached implementation than it will be worth our trouble. Especially if it enables us to build a Erlang Framework to support any scalable idea we can come up with.
So if the idea of scalable server applications, functional programming or Erlang in general seems interesting, I highly suggest you check out Programming Erlang.
Joe Armstrong, one of the creators of the Erlang language, has recently published a new book on the topic and its truly a fascinating read.
One of the biggest complaints I hear from other developers about any introductory level book about a new programming language is the lack of useful programs that can be created upon completion of the book. What I mean is that you may be able to do the normal "Hello World", Fibonacci sequence output, etc. - but you probably won't be able to do anything really useful. This isn't the case with Armstrong's book.
The main ideas of the book and of Erlang (free for most environments at http://www.erlang.org) in general is concurrency or the simultaneous execution of code. While C and its variants offer multi-threading, it is still essentially executing sequential code and hence subject to deadlocks, race-conditions, etc. Erlang enforces some strict rules from the get-go to support concurrency and allow for true simultaneous execution that is free from not only race-conditions and deadlocks, but from semaphores, mutexes and locks as well.
In order to do that, Erlang turns computer science on its head (from a sequential programming point-of-view) which Armstrong is quick to point out at every turn. For example, variables are only called as such because it makes things easier. The fact is they can't actually vary and an Exception is thrown if you even try.
On that same note, the equal sign is not the assignment operator like it usually is in programming, it is instead used to perform pattern matching. An example would probably work best to explain it:
1>X = 5.
5
2>X = 5.
5
3>X = 3.
=ERROR REPORT==== 16-Oct-2007::21:26:12 ===
Error in process <0.30.0> with exit value: {{badmatch,3},[{erl_eval,expr,3}]}
** exited: {{badmatch,3},[{erl_eval,expr,3}]} **
As I stated before, the = is not the assignment operator, it is instead used for pattern matching. An additional caveat though, when used with an uninitialized variable (which usually start with Capital letters), the variable is assigned that value. In line 1 above, we match the variable X against the literal value 5. Since X is uninitialized at the time we match it against the literal 5, it then takes on that value.
This is why, when we repeat the action in the second line, it returns the value 5 (indicating a match). Consequently, when we hit the third line, the shell throws an exception since we're matching X against 3, when it has already taken on the value 5.
You may wonder what the value of such an operator is, but when you dive into server programming, you'll see that it can be used (among other things) to direct functionality within network protocols. By matching against certain patterns, you can essentially code mini-conditional statements to perform various actions upon receipt of certain data. It seems complicated, but it's really not - since this is a Book Review and not an Introduction to Erlang, so I'll leave the explanation to Armstrong...
Within 75 pages, I had gained an enthusiasm for Erlang that was apparently infectious and it has been embraced by a few other developers in my Department (including Jon over at Rusty Razor Blade). While we're still not 100% sure it will be able to support the traffic load and perform fast enough, we're motivated enough to try. Armstrong makes it easy to learn from example too, since the book contains Erlang source to create a server for almost any major network protocol or project you could think of including IRC, SHOUTcast, a simple Error logger, a SQL Server and a Web Server.
We've discussed a plethora of different ideas we could run on our "new Erlang Framework", some more ambitious than others. We're convinced we could rewrite memcached in a few hundred lines of code, including all the features of the original - a few that are missing and commonly implemented in other cache systems - as well as a few of our own custom design. We figure if we can even get 80% of the throughput of our current memcached implementation than it will be worth our trouble. Especially if it enables us to build a Erlang Framework to support any scalable idea we can come up with.
So if the idea of scalable server applications, functional programming or Erlang in general seems interesting, I highly suggest you check out Programming Erlang.
0 comments
10 Things This Skeptic Loves About Python's Syntax
August 15, 2007 • 9:38AM • permalink
First, a note...
Anyone that has worked with me in the past will know what a skeptic I am about new programming languages. I use a lot of different languages (new and old) and operating systems (mostly to fit the constraints of my client's environments) but I prefer to work in C++/C# and in Microsoft Visual Studio. I am always reading one tech book or another, so as a change of pace I started doing some random reading about Python.
While I still prefer C++/C#, the seamless integration of Python with C is very appealing. There is no question that Python is a RAD programming language, especially when looking over the syntax. I wanted to mention ten of my favorites, although there are many more than this - and I've just started learning it! I'm going to give very simple explanations to save space, but I suggest if you find the below interesting that you consider learning Python.
(Please note that the below are in no specific order.)
Divide-and-Floor Operator //
This is an additional divide operator that is used to truncate the entire decimal portion. This is a full truncation of the number with no rounding involved. Since this is a fairly common operation when dealing with floating-point numbers, it's nice to have a simple operator to handle it.
print 10.0 / 3
print 10.0 // 3
x = 10.0
x //= 3
print x
Multiple Assignments In One Statement
Why waste space and time when you need to get things done? Python allows you to perform multiple actions in one statement through use of a comma. Items on either end of the equals sign are indexed in order, as seen here:
x, y = 1, 2
print x + y
increment, decrement = x + y, x - y
print increment, decrement
Scope Delimiters
Python takes a very unique way of delimiting blocks of code: by using whitespace. Lines of code with the same indentations (after the start of a conditional block of code or other scoped construct) are considered part of the same block.
if x > 3:
print 'this is inside the if-statement'
print 'this is too!'
print 'this is executed regardless of whether x is greater than 3'
sprintf Operator %
StringBuilder.AppendFormat is probably one of the .NET functions that I use the most. At 26 letters, even with Intellisense, it's a handful.
Python has a much simpler way of doing the same thing:
print "I eat about %0.2f times every %d days" % (123.456789, 10)
Use of the else Keyword with Loops
Python allows you to append an else clause to both while and for loops that always execute when a break clause is not executed inside the conditional block.
In many situations this allows for the elimination of some branching logic, in addition to allowing developers to remove an additional variable, in many cases, that would only serve to act as a flag for whether or not the intended case executed.
A common example is to implement simple search functionality:
search_number = 699
for i in range(1, 1000):
if (i == search_number):
print 'your number was found'
break
else:
print 'your number was not found'
search_number = 10000
for i in range(1, 1000):
if (i == search_number):
print 'your number was found'
break
else:
print 'your number was not found'
Slice Operator [:]
Nevermind taking a portion of a string, this technique can also be used to take a subset of a list or a dictionary (Python's version of arrays/vectors and hashtables). The example below uses a list.
L = [1, 2, 3, 4, 5, 6]
print L[2:4]
print L[2:]
print L[:3]
print L[:]
Step Operator [::]
This is really an additional parameter to the Slice Operator, but this determines the direction and quantity of the index increment (or decrement), as if iterating through the list. It's best to show with an example or three:
L = [1, 2, 3, 4, 5, 6]
print L[::-1]
print L[::3]
print L[::-2]
Note that this can (obviously) be combined with the Slice Operator above to change the rate of index through sublists. As a continuation from the example above:
print L[:1:-1]
Optional Function Arguments (* and ** Operators)
The whole reason you can use a different programming language in a given situation is the fundamental rule that you should always use the right tool for the right job. In Python, these are known as Arbitrary Function Arguments.
Python gives developers several options (and several combinations of the options) that can be used when using function overloading with optional arguments.
The first is the * operator which returns the remaining arguments of a function in a Python data type known as a tuple.
def SomeFunction(first_arg, *other_args):
print len(other_args)
SomeFunction('test', 'test2', 'test3', 4)
The other operator is the **operator which performs the same action, only returning a dictionary instead of a tuple. This only works with named arguments and will automatically map the argument name to the requested value.
def SomeFunction(**the_args):
print the_args
SomeFunction(a=1, b=2, c=3, d=4, e=5, f=6)
Multiple Comparison Operators
Unlike C and most other languages, Python allows you to chain the various comparison operations together to form complex expressions, just like in algebra. Note that like other boolean expressions, these are short-circuited to increase performance.
a = 1
b = 3
c = 5
print a < b < c
print c < b < a
Stop Reinventing the Wheel
Finally, Python takes many higher level constructs and implementations that have been propagated into multiple languages over the years.
Three (out of more than I can easily count) are shown below: simple string duplication, (theoretically) infinitely sized numbers and the Complex number type. These are shown very briefly below:
print "*" * 20
print 2 ** 100
x = 1 + 3j
y = 1 - 3j
print x * y
If you've ever programmed in any other language, you can see that Python has an extremely unique syntax. It is very unique, but surprisingly intuitive once you've begun to use it. The above is only a small example of how Python syntax varies from other languages. Now, I finally understand what people mean when they refer to Python code as being very "un-Python-like". Since Python supports most of the basic constructs of other languages, it's very easy to do most actions one of two ways: the normal way and the Python way.
Anyone that has worked with me in the past will know what a skeptic I am about new programming languages. I use a lot of different languages (new and old) and operating systems (mostly to fit the constraints of my client's environments) but I prefer to work in C++/C# and in Microsoft Visual Studio. I am always reading one tech book or another, so as a change of pace I started doing some random reading about Python.
While I still prefer C++/C#, the seamless integration of Python with C is very appealing. There is no question that Python is a RAD programming language, especially when looking over the syntax. I wanted to mention ten of my favorites, although there are many more than this - and I've just started learning it! I'm going to give very simple explanations to save space, but I suggest if you find the below interesting that you consider learning Python.
(Please note that the below are in no specific order.)
Divide-and-Floor Operator //
This is an additional divide operator that is used to truncate the entire decimal portion. This is a full truncation of the number with no rounding involved. Since this is a fairly common operation when dealing with floating-point numbers, it's nice to have a simple operator to handle it.
print 10.0 / 3
#prints 3.3333333333333335
print 10.0 // 3
#prints 3.0
x = 10.0
x //= 3
print x
#prints 3.0
Multiple Assignments In One Statement
Why waste space and time when you need to get things done? Python allows you to perform multiple actions in one statement through use of a comma. Items on either end of the equals sign are indexed in order, as seen here:
x, y = 1, 2
print x + y
#prints 3
increment, decrement = x + y, x - y
print increment, decrement
#prints 3, -1
Scope Delimiters
Python takes a very unique way of delimiting blocks of code: by using whitespace. Lines of code with the same indentations (after the start of a conditional block of code or other scoped construct) are considered part of the same block.
if x > 3:
print 'this is inside the if-statement'
print 'this is too!'
print 'this is executed regardless of whether x is greater than 3'
sprintf Operator %
StringBuilder.AppendFormat is probably one of the .NET functions that I use the most. At 26 letters, even with Intellisense, it's a handful.
Python has a much simpler way of doing the same thing:
print "I eat about %0.2f times every %d days" % (123.456789, 10)
#prints I eat about 123.46 times every 10 days
Use of the else Keyword with Loops
Python allows you to append an else clause to both while and for loops that always execute when a break clause is not executed inside the conditional block.
In many situations this allows for the elimination of some branching logic, in addition to allowing developers to remove an additional variable, in many cases, that would only serve to act as a flag for whether or not the intended case executed.
A common example is to implement simple search functionality:
search_number = 699
for i in range(1, 1000):
if (i == search_number):
print 'your number was found'
break
else:
print 'your number was not found'
#prints your number was found
search_number = 10000
for i in range(1, 1000):
if (i == search_number):
print 'your number was found'
break
else:
print 'your number was not found'
#prints your number was not found
Slice Operator [:]
Nevermind taking a portion of a string, this technique can also be used to take a subset of a list or a dictionary (Python's version of arrays/vectors and hashtables). The example below uses a list.
L = [1, 2, 3, 4, 5, 6]
#a (0-based) list
print L[2:4]
#prints [3, 4]
print L[2:]
#prints [3, 4, 5, 6]
print L[:3]
#prints [1, 2, 3]
print L[:]
#prints [1, 2, 3, 4, 5, 6]
Step Operator [::]
This is really an additional parameter to the Slice Operator, but this determines the direction and quantity of the index increment (or decrement), as if iterating through the list. It's best to show with an example or three:
L = [1, 2, 3, 4, 5, 6]
#a (0-based) list
print L[::-1]
#prints [6, 5, 4, 3, 2, 1]
print L[::3]
#prints [1, 4]
print L[::-2]
#prints [6, 4, 2]
Note that this can (obviously) be combined with the Slice Operator above to change the rate of index through sublists. As a continuation from the example above:
print L[:1:-1]
#prints [6, 5, 4, 3]
Optional Function Arguments (* and ** Operators)
The whole reason you can use a different programming language in a given situation is the fundamental rule that you should always use the right tool for the right job. In Python, these are known as Arbitrary Function Arguments.
Python gives developers several options (and several combinations of the options) that can be used when using function overloading with optional arguments.
The first is the * operator which returns the remaining arguments of a function in a Python data type known as a tuple.
def SomeFunction(first_arg, *other_args):
print len(other_args)
SomeFunction('test', 'test2', 'test3', 4)
#prints 3
The other operator is the **operator which performs the same action, only returning a dictionary instead of a tuple. This only works with named arguments and will automatically map the argument name to the requested value.
def SomeFunction(**the_args):
print the_args
SomeFunction(a=1, b=2, c=3, d=4, e=5, f=6)
#prints {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6}
Multiple Comparison Operators
Unlike C and most other languages, Python allows you to chain the various comparison operations together to form complex expressions, just like in algebra. Note that like other boolean expressions, these are short-circuited to increase performance.
a = 1
b = 3
c = 5
print a < b < c
#prints True
print c < b < a
#prints False
Stop Reinventing the Wheel
Finally, Python takes many higher level constructs and implementations that have been propagated into multiple languages over the years.
Three (out of more than I can easily count) are shown below: simple string duplication, (theoretically) infinitely sized numbers and the Complex number type. These are shown very briefly below:
#1) Simple String Extension
print "*" * 20
#prints ********************
#2) Infinitely Sized Numbers (based on Memory Limits)
#Note that ** is the exponent operator in Python.
#Normally 2 ** 64 is the long type limit in most systems.
print 2 ** 100
#prints 1267650600228229401496703205376L
#3) Complex Number Type
x = 1 + 3j
y = 1 - 3j
print x * y
#prints (10+0j)
If you've ever programmed in any other language, you can see that Python has an extremely unique syntax. It is very unique, but surprisingly intuitive once you've begun to use it. The above is only a small example of how Python syntax varies from other languages. Now, I finally understand what people mean when they refer to Python code as being very "un-Python-like". Since Python supports most of the basic constructs of other languages, it's very easy to do most actions one of two ways: the normal way and the Python way.
|
page 1 of 1
|
