Here's the link.
And they were hoping to accomplish what, exactly? I've never heard of geeklist before, and I don't expect them to be in business very long. If I had given them funding, I'd be kicking myself.
Even if they thought they were right (they're not) you have to know how to pick your battles. Some people are just too emotional for the business world.
Monday, March 26, 2012
Sunday, March 18, 2012
Clojure with Python syntax
This post is of the brainstorming variety. It is a project that I might undertake in the future, when I have time.
Many programmers (not me, but apparently a large number) find Python to be a readable language, and Lisp to not be readable. You give up macros when using Python, but maybe that's not a big deal to many developers. Maybe if you're running a company with a lot of turnover, macros aren't a big deal. Or maybe you just don't understand or don't care about macros. I love them but they can be hard to get right.
So what if there was a language with Python syntax, complete with whitespace rules, that compiled to Clojure? My google-fu did not find any such projects. Clojure is a really good language even without macros. The code generated by the new language would be trivially interoperable with any other Clojure code.
It would have to make available everything that is in Clojure. I have no idea how much work it would be to:
The goals would be:
Many programmers (not me, but apparently a large number) find Python to be a readable language, and Lisp to not be readable. You give up macros when using Python, but maybe that's not a big deal to many developers. Maybe if you're running a company with a lot of turnover, macros aren't a big deal. Or maybe you just don't understand or don't care about macros. I love them but they can be hard to get right.
So what if there was a language with Python syntax, complete with whitespace rules, that compiled to Clojure? My google-fu did not find any such projects. Clojure is a really good language even without macros. The code generated by the new language would be trivially interoperable with any other Clojure code.
It would have to make available everything that is in Clojure. I have no idea how much work it would be to:
- Parse a Pythonesque language
- Provide access to everything in Clojure core
- Keep up with all new releases of Clojure
- Write documentation
- Produce Clojure code that is easy to read and modify (should not be difficult)
The goals would be:
- Eliminate the Lisp syntax barrier to getting programmers to try Clojure.
- Make Clojure acceptable to universities that want to avoid Lisp syntax.
- Provide a stepping stone so that programmers can learn Clojure concepts, then when they want more control over their language, they can start writing Clojure without giving up any of their existing code.
Wednesday, March 14, 2012
What I learned showing Clojure to others
Here are a few things I've noticed when I've (attempted to) show Clojure to others. I'm not saying that my sample (n=4) is representative, so if you think that is too small a sample size, there's no point reading further. I sat down at the computer to demonstrate to two, and had lengthy discussions with the other two.
1. (Not important) The name is unusual, and they've never heard of it. When I tell them that it runs on the JVM, you have access to all Java libraries, and that there is a large, helpful community with four - soon to be five - books published by major publishers, they view it as credible. Outstanding libraries written in Clojure, like Incanter, also help.
2. (Critical) After they realize it's not a toy language, the next question is ease of use. I was surprised that ease of use has nothing to do with the language itself. How can I make an executable that I can share with others? How can I access existing libraries? And it has to be something automatic, where you write the code, make the executable, and then you can run it by clicking the mouse or issuing a simple command.
This is where Clojure fails, big time. The claim is made that you don't need to know Java to use Clojure. That's false. You need a lot of knowledge of the Java build system, how to set the classpath, etc. True, you don't need to know much about Java the language, but you need to know a lot about Java the development environment. And you're not likely to learn much about it from the Clojure community, unfortunately, because it's expected you can learn it yourself. This is a big burden to impose on someone who wants to learn Clojure.
Counterclockwise helps a lot. It's dead simple to get started with a feature-filled Eclipse development environment. Got some Java libraries you want to access? Click a couple times to add them to your project. Want to use infix notation and a random number generator? Add the Incanter .jar executable in a couple clicks. Don't want to mess with the classpath? You don't have to.
Unfortunately I still haven't got the whole making a .jar figured out myself. There's still a long way to go in this area. Clojure has to free itself from the Java approach or it's only going to appeal to Enterprise Java developers looking for a good Lisp. The requirement that you understand and accept the Java approach was, to be honest, a dealbreaker. None of the four had much experience with Java (mostly by choice) and they were not interested in learning a whole new approach to software development plus Java.
3. (Sort of important) The parenthesis issue is really a non-issue. Whitespace is actually a bigger deal in Clojure than in Python. There's just so dang much indentation, and indentation is syntax, and there are so many levels of indentation in both directions in a single block of code.
4. (Very important) The typical approach to writing in any Lisp is to do a lot of nesting. "let" helps, but all the indentation I referred to above is due to nesting. You have to follow everything in a given line plus everything in indented lines below it to know what's going on. You don't usually see something like that in imperative code. Another thing is that using operators in prefix form is stupid. "+" is an infix operator. It should be possible to make infix operators the default.
5. (Hard to classify) They don't understand the importance of functional programming.
6. (Important) They like the idea of a customizable programming language. They customize everything else in their lives, so they were very open to the idea that you can customize your language. I think everyone would like to change something in their current language, so macros have appeal.
The most important thing I took away is that their evaluation of Clojure had almost nothing to do with the language itself, beyond the concept of macros, which they liked but didn't really understand. I think it's important to explain before you even start why the syntax is "funny". There's no reason to hide macros, they are a killer feature.
I realized that most of the world doesn't care all that much about programming languages. They are not interested in learning about new programming concepts, and if they've never thought about the basics of functional programming, they're not going to care if a new language supports it.
It's also obvious why Python is popular. If you like imperative programming, and you don't want to customize your language, Python can probably make you happy. I don't see Clojure having the same broad appeal any time soon.
1. (Not important) The name is unusual, and they've never heard of it. When I tell them that it runs on the JVM, you have access to all Java libraries, and that there is a large, helpful community with four - soon to be five - books published by major publishers, they view it as credible. Outstanding libraries written in Clojure, like Incanter, also help.
2. (Critical) After they realize it's not a toy language, the next question is ease of use. I was surprised that ease of use has nothing to do with the language itself. How can I make an executable that I can share with others? How can I access existing libraries? And it has to be something automatic, where you write the code, make the executable, and then you can run it by clicking the mouse or issuing a simple command.
This is where Clojure fails, big time. The claim is made that you don't need to know Java to use Clojure. That's false. You need a lot of knowledge of the Java build system, how to set the classpath, etc. True, you don't need to know much about Java the language, but you need to know a lot about Java the development environment. And you're not likely to learn much about it from the Clojure community, unfortunately, because it's expected you can learn it yourself. This is a big burden to impose on someone who wants to learn Clojure.
Counterclockwise helps a lot. It's dead simple to get started with a feature-filled Eclipse development environment. Got some Java libraries you want to access? Click a couple times to add them to your project. Want to use infix notation and a random number generator? Add the Incanter .jar executable in a couple clicks. Don't want to mess with the classpath? You don't have to.
Unfortunately I still haven't got the whole making a .jar figured out myself. There's still a long way to go in this area. Clojure has to free itself from the Java approach or it's only going to appeal to Enterprise Java developers looking for a good Lisp. The requirement that you understand and accept the Java approach was, to be honest, a dealbreaker. None of the four had much experience with Java (mostly by choice) and they were not interested in learning a whole new approach to software development plus Java.
3. (Sort of important) The parenthesis issue is really a non-issue. Whitespace is actually a bigger deal in Clojure than in Python. There's just so dang much indentation, and indentation is syntax, and there are so many levels of indentation in both directions in a single block of code.
4. (Very important) The typical approach to writing in any Lisp is to do a lot of nesting. "let" helps, but all the indentation I referred to above is due to nesting. You have to follow everything in a given line plus everything in indented lines below it to know what's going on. You don't usually see something like that in imperative code. Another thing is that using operators in prefix form is stupid. "+" is an infix operator. It should be possible to make infix operators the default.
5. (Hard to classify) They don't understand the importance of functional programming.
6. (Important) They like the idea of a customizable programming language. They customize everything else in their lives, so they were very open to the idea that you can customize your language. I think everyone would like to change something in their current language, so macros have appeal.
The most important thing I took away is that their evaluation of Clojure had almost nothing to do with the language itself, beyond the concept of macros, which they liked but didn't really understand. I think it's important to explain before you even start why the syntax is "funny". There's no reason to hide macros, they are a killer feature.
I realized that most of the world doesn't care all that much about programming languages. They are not interested in learning about new programming concepts, and if they've never thought about the basics of functional programming, they're not going to care if a new language supports it.
It's also obvious why Python is popular. If you like imperative programming, and you don't want to customize your language, Python can probably make you happy. I don't see Clojure having the same broad appeal any time soon.
Monday, March 12, 2012
A quick look at clojure-py
I played around with clojure-py this weekend. I jotted down some initial thoughts on the advantages of Clojure in pure Python in an earlier post.
Before I start, I want to point out that this is a very young project. My goal was only to get a feel for how things will work when there is a stable, well-tested release. I was impressed with what I saw and will happily await future releases. One to two years is a reasonable time frame for a production quality release on a project of this size. Users (myself included) have no reason to expect any specific functionality to work. We should expect bugs. I want to clarify these points because sometimes readers see something negative like "x doesn't work" and think I've written "Those incompetent developers haven't even implemented x. What a joke. Sigh."
I followed the instructions on the project wiki to install using easy_install. Consistent with the name, the install was easy. I started the REPL at the (Linux) command line using "clojurepy". I was greeted by
clojure-py 0.1.0
user=>
The starting point with any language has to be "Hello, World!":
(println "Hello, World!")
Okay, that's great, but what about something real? There are supposed to be 350 Clojure functions implemented, but I'm not sure which ones they are (reduce and ref are not).
Functions
Define a function:
(defn f [x y z] (+ x y z))
Call it:
(f 3 4.2 7.6)
(f 3, 4.2, 7.6)
clojure-py lets you use commas between arguments. The prefix notation is kind of ugly. Incanter offers infix notation, complete with operator precedence, so you could instead define f using
(defn f [x y z] ($= x + y + z))
Unfortunately ref is not yet implemented, so the Incanter infix library cannot be used. (I'm sure it could be made to work, but at this early stage it's wiser to let the language catch up.)
Multiple Arity
Let's try out multiple arity functions:
(defn sum
([x y]
(+ x y))
([x y z]
(+ x y z)))
(sum 1 2)
(sum 1 2 3)
That works. Now I can avoid prefix operators. This is not a functional solution, and it's pretty lengthy by Lisp standards, so let me use less code to sum an arbitrary number of arguments:
(defn sum [& stuff] (apply + stuff))
The [& stuff] indicates that the function takes a variable number of arguments, which will all be put into "stuff". (apply + stuff) applies the function "+" to all the elements of "stuff". Test it out:
(sum 1 2 3)
(sum 1 2 47.56 13 12 11 10 9)
(sum)
It works. clojure-py is clearly beyond the initial prototype stage; one could write complicated programs at this point.
Accessing Python Libraries
Enough with the pure Clojure stuff. It's nice to see that clojure-py is at such an advanced state but I can do all that and more on the JVM. The cool thing about clojure-py is that you can import existing Python libraries. That may not be helpful in a lot of areas (Java probably has more good quality libraries than any other language) but for numerical computing it is huge.
That includes scipy, Rpy2 to call R, and f2py to call Fortran, among many others. Presumably that also means you could call Pycuda from clojure-py, adding GPU computing to the things you can do from Clojure. I can only imagine the possibilities for using Clojure for GPU metaprogramming. cuda programming is not fun.
Python Standard Library
First I pulled some examples from the Python standard library tutorial. I created a namespace and added everything from the math library:
(ns tryclojure (:require math))
(math/cos 1.5)
(math/cos (/ math/pi 4))
(math/log 1024 2)
(random/choice ["apple" "pear" "banana"])
Oops, that last call throws an error. Let's add random to our namespace, but we want only two functions:
(ns tryclojure
(:require [random :only [choice random]]))
(random/choice ["apple" "pear" "banana"])
(random/sample (py/range 10) 10)
(random/random)
The second example shows how to access functions like range that don't have to be imported into Python. You do not have to explicitly import them into clojure-py either.
Numpy
Now give numpy a try. I'd rather write np than numpy, so I can use the :as keyword.
(ns tryclojure
(:require [numpy :as np]))
(np/arange 10)
(* 3 (np/arange 10))
(def x (np/array [1 2 3]))
(def y (np/array [4 5 6]))
(* x y)
(def a (np/array [[1 2] [3 4]]))
(def b (transpose a))
(dot a b)
I'm using arrays rather than matrices, so matrix multiplication is done with dot. (* a b) is element-by-element multiplication. The numpy syntax requires only two arguments to dot, so if you want to compute a*b*b*a, you have to do (dot (dot (dot a b) b) a). You should avoid nesting like that unless you have a very good reason. Nesting like that is only a little easier to follow than GOTO statements in idiomatic FORTRAN 66.
Threading Macro
Let's see if the threading macro is available. Don't worry if you don't know what it is, but it does simplify things. An example is (-> (dot 3.0) (/ 2)), which returns 1.5. It evaluates the first argument and uses it as the first argument of the next call.
(-> (dot a b) (dot b) (dot a))
I could also just use temporary variables in a let statement, which is verbose, but fine if you're a Clojure newbie or plan to share code with a Clojure newbie:
(let [temp-1 (dot a b)
temp-2 (dot temp-1 b)]
(dot temp-2 a))
Conclusions
If you want to add Clojure syntax and basic functionality to Python, it looks like you've already got most of what you need. I hope clojure-py eventually implements all of JVM Clojure and then provides a way to pass messages from one implementation to the other. Great work by the developers.
Before I start, I want to point out that this is a very young project. My goal was only to get a feel for how things will work when there is a stable, well-tested release. I was impressed with what I saw and will happily await future releases. One to two years is a reasonable time frame for a production quality release on a project of this size. Users (myself included) have no reason to expect any specific functionality to work. We should expect bugs. I want to clarify these points because sometimes readers see something negative like "x doesn't work" and think I've written "Those incompetent developers haven't even implemented x. What a joke. Sigh."
I followed the instructions on the project wiki to install using easy_install. Consistent with the name, the install was easy. I started the REPL at the (Linux) command line using "clojurepy". I was greeted by
clojure-py 0.1.0
user=>
The starting point with any language has to be "Hello, World!":
(println "Hello, World!")
Okay, that's great, but what about something real? There are supposed to be 350 Clojure functions implemented, but I'm not sure which ones they are (reduce and ref are not).
Functions
Define a function:
(defn f [x y z] (+ x y z))
Call it:
(f 3 4.2 7.6)
(f 3, 4.2, 7.6)
clojure-py lets you use commas between arguments. The prefix notation is kind of ugly. Incanter offers infix notation, complete with operator precedence, so you could instead define f using
(defn f [x y z] ($= x + y + z))
Unfortunately ref is not yet implemented, so the Incanter infix library cannot be used. (I'm sure it could be made to work, but at this early stage it's wiser to let the language catch up.)
Multiple Arity
Let's try out multiple arity functions:
(defn sum
([x y]
(+ x y))
([x y z]
(+ x y z)))
(sum 1 2)
(sum 1 2 3)
That works. Now I can avoid prefix operators. This is not a functional solution, and it's pretty lengthy by Lisp standards, so let me use less code to sum an arbitrary number of arguments:
(defn sum [& stuff] (apply + stuff))
The [& stuff] indicates that the function takes a variable number of arguments, which will all be put into "stuff". (apply + stuff) applies the function "+" to all the elements of "stuff". Test it out:
(sum 1 2 3)
(sum 1 2 47.56 13 12 11 10 9)
(sum)
It works. clojure-py is clearly beyond the initial prototype stage; one could write complicated programs at this point.
Accessing Python Libraries
Enough with the pure Clojure stuff. It's nice to see that clojure-py is at such an advanced state but I can do all that and more on the JVM. The cool thing about clojure-py is that you can import existing Python libraries. That may not be helpful in a lot of areas (Java probably has more good quality libraries than any other language) but for numerical computing it is huge.
That includes scipy, Rpy2 to call R, and f2py to call Fortran, among many others. Presumably that also means you could call Pycuda from clojure-py, adding GPU computing to the things you can do from Clojure. I can only imagine the possibilities for using Clojure for GPU metaprogramming. cuda programming is not fun.
Python Standard Library
First I pulled some examples from the Python standard library tutorial. I created a namespace and added everything from the math library:
(ns tryclojure (:require math))
(math/cos 1.5)
(math/cos (/ math/pi 4))
(math/log 1024 2)
(random/choice ["apple" "pear" "banana"])
Oops, that last call throws an error. Let's add random to our namespace, but we want only two functions:
(ns tryclojure
(:require [random :only [choice random]]))
(random/choice ["apple" "pear" "banana"])
(random/sample (py/range 10) 10)
(random/random)
The second example shows how to access functions like range that don't have to be imported into Python. You do not have to explicitly import them into clojure-py either.
Numpy
Now give numpy a try. I'd rather write np than numpy, so I can use the :as keyword.
(ns tryclojure
(:require [numpy :as np]))
(np/arange 10)
(* 3 (np/arange 10))
(def x (np/array [1 2 3]))
(def y (np/array [4 5 6]))
(* x y)
(def a (np/array [[1 2] [3 4]]))
(def b (transpose a))
(dot a b)
I'm using arrays rather than matrices, so matrix multiplication is done with dot. (* a b) is element-by-element multiplication. The numpy syntax requires only two arguments to dot, so if you want to compute a*b*b*a, you have to do (dot (dot (dot a b) b) a). You should avoid nesting like that unless you have a very good reason. Nesting like that is only a little easier to follow than GOTO statements in idiomatic FORTRAN 66.
Threading Macro
Let's see if the threading macro is available. Don't worry if you don't know what it is, but it does simplify things. An example is (-> (dot 3.0) (/ 2)), which returns 1.5. It evaluates the first argument and uses it as the first argument of the next call.
(-> (dot a b) (dot b) (dot a))
I could also just use temporary variables in a let statement, which is verbose, but fine if you're a Clojure newbie or plan to share code with a Clojure newbie:
(let [temp-1 (dot a b)
temp-2 (dot temp-1 b)]
(dot temp-2 a))
Conclusions
If you want to add Clojure syntax and basic functionality to Python, it looks like you've already got most of what you need. I hope clojure-py eventually implements all of JVM Clojure and then provides a way to pass messages from one implementation to the other. Great work by the developers.
Sunday, March 04, 2012
I don't think web developers should talk about programming
Web developers, I'll let you in on a secret. I know you've never heard this outside of your small circle of friends. It'll probably come as a shock.
Programming is not a subset of web development. It is possible to write programs that are not part of a website.
I know you won't believe me.
Today's award for "Headline I'd Never Write" goes to this gem:
What Every Programmer Should Know About SEO
No, I didn't read the article. The answer is "absolutely nothing". I'm not about to read something written by someone who worked his way through a Ruby on Rails tutorial and thinks he can tell me something interesting. Why not "What Every Shoe Salesman Should Know About SEO"? When you write R and Fortran code most of the day, SEO is just as relevant.
I don't even see why every web developer should be concerned about SEO. I know some folks who work on complicated web apps, but it wouldn't be very helpful for their work to know anything about SEO, because that's not their department.
Not that I haven't seen similar many, many times before. I can't find the link, but there was a blog post a few months ago that said Scala and Clojure have nothing to offer because all programmers are web developers and web developers don't need to worry about concurrency.
Programming is not a subset of web development. It is possible to write programs that are not part of a website.
I know you won't believe me.
Today's award for "Headline I'd Never Write" goes to this gem:
What Every Programmer Should Know About SEO
No, I didn't read the article. The answer is "absolutely nothing". I'm not about to read something written by someone who worked his way through a Ruby on Rails tutorial and thinks he can tell me something interesting. Why not "What Every Shoe Salesman Should Know About SEO"? When you write R and Fortran code most of the day, SEO is just as relevant.
I don't even see why every web developer should be concerned about SEO. I know some folks who work on complicated web apps, but it wouldn't be very helpful for their work to know anything about SEO, because that's not their department.
Not that I haven't seen similar many, many times before. I can't find the link, but there was a blog post a few months ago that said Scala and Clojure have nothing to offer because all programmers are web developers and web developers don't need to worry about concurrency.
Subscribe to:
Posts (Atom)