
Do I Really Need a Programming Language? - momo-reina
http://ayudasystems.tumblr.com/post/71327185334/do-i-really-need-a-programming-language
======
tikhonj
The real question here is "do I need syntax?", or, more precisely, "do I
really need a [complex] grammar?" Any given Lisp is still a programming
language--it has _some_ syntax and it has semantics. But it does have a _much_
simpler grammar than any language (save Forth).

The grammars exist because programs are made to be read by people, not just
computers. A more heterogeneous notation can make for more concise code that's
easier to scan and easier to read.

Of course, this is not to say that Lisp is unreadable. I actually rather like
reading and writing (paredit is _awesome_ ) Lisp code. But, after quite a bit
of Racket, I've found that I still heavily prefer having infix operators and a
bit more syntax. At the same time, I also often want _less_ noise--ie no
parentheses. I want all this so that I can quickly scan and comfortably read
my code. That's why we need grammars.

~~~
bad_user
I think a more helpful question would be "in what instances do I need
syntax?". Could you build a type-system like Haskell has for LISP? Would it be
usable?

In terms of syntax, I think there's a divide between the needs of static type-
systems, versus dynamic ones. LISP is at its core a dynamic language. It makes
sense to treat code as being data that can be manipulated. Getting rid of all
that syntax gives you great power in terms of what you can do. And personally
I find Clojure code to be much saner than code written in Ruby or Python, but
that's another discussion.

However, the other side of the coin are Haskell or Miranda (its predecessor)
or languages in the ML family or Scala. These languages go to great length to
achieve much of LISP's expressiveness, while ensuring a great amount of static
type-enforcement. Haskell is especially notable because Haskell is lazy and
has many goodies, such as type-classes or rank-2 types. People say that when a
piece of Haskell code successfully compiles it is usually correct. LISP can't
do this, even though there have been experiments with pluggable type-systems.

For an excellent rant on the choice of Scheme for SICP (and not Miranda,
Haskell's predecessor), checkout:
[http://www.cs.kent.ac.uk/people/staff/dat/miranda/wadler87.p...](http://www.cs.kent.ac.uk/people/staff/dat/miranda/wadler87.pdf)

So IMHO, syntax helps if you want static type-safety, because the language and
the type-system exposed need to be expressive. Whether static type-safety is
useful or not, it's a matter of debate, being highly dependent on the problem
domain. One could argue that static type-safety is very useful if the shape of
the data you're manipulating is well defined and doesn't change much,
otherwise you're better off with a dynamic language, but that's another
discussion.

~~~
colomon
"People say that when a piece of Haskell code successfully compiles it is
usually correct."

Every time I see this claim, I wonder what the heck people are working on that
is so simple that getting the types right is all it takes to get the code
right? Is it just that enough of my work is math or parsing, both of which
typically have an infinite number of ways to get things wrong but with the
correct types?

Or is the idea really the other way around -- if your program is sufficiently
complex, you'll never get it to actually pass Haskell's type checks?

Edited to add, I love the article you linked to so far. :)

~~~
andrewflnr
I had some similar experiences in OCaml recently, so I might be able to shed
some light on this. I found that that when compiling code, the result was
often one of three things: one, type checking failed (or I got an inexhaustive
match warning), and I got a useful message, two, it worked, and three, it
failed but the problem was fairly obvious when I saw it. Functional
programming, for me, is a fairly direct way of expressing the algorithm in my
head, so the basic idea tends to be much more fully fleshed out the first time
I write it down in code.

Sometimes I got a type error from some bizzare syntax mistake, usually failing
to correctly delineate an expression, and sometimes the algorithm in my head
was just wrong and I had to fix it. At that point, the cycle starts over, and
the same benefits I mentioned above help in debugging. FWIW, the problem I was
working on was fairly simple, but novel. I was a very happy camper this
Christmas, working with OCaml, despite its syntax.

Out of curiosity, what language do you do your "math and parsing" in? OCaml
might be a good fit.

~~~
colomon
I do most of my $work programming in C++. (Not out of any great love for the
language, mind you.)

To give a somewhat extreme example of the sort of stuff I do -- one of my
current projects is to try to create a first-class fillet surface type [1] for
the geometry engines I work with. My current code converts each fillet to a
NURBS surface, but this is slow, consumes a lot of memory, and produces
surfaces which frequently are not accurate enough for my purposes. So my hope
is to be able to directly calculate points on the fillet and their
derivatives.

It's easy enough to calculate points on the fillet surface, but I don't see
any obvious way of directly calculating the derivative along the surface. So
I've been investigating Chebyshev polynomials in two variables. But that
algorithm looks a bit hairy, and I don't have any feel for whether it will be
an actual improvement in practice. (And having written all this, I'm suddenly
wondering if I'm making every effort to sort out the simple cases that are
easy to solve exactly.)

My point here is that figuring out the correct types involved seems like a
tiny, tiny part of the required work. Maybe it's because I haven't put in
enough time in Haskell, but I don't see how stricter than C++ types are going
to help. The real work is getting the math correct and fast enough to be
useful.

By the way, my comment is not meant to be a dig at Haskell (et al). I'm not
sold on it as a language, but it certainly has a lot of interesting ideas --
pattern matching and laziness spring to mind.

[1]
[http://en.wikipedia.org/wiki/Fillet_(mechanics)](http://en.wikipedia.org/wiki/Fillet_\(mechanics\))

~~~
phob
Often when using C++ I find myself solving C++ problems, not real problems. In
a domain with very difficult math and performance challenges, the C++ problems
will be dwarfed by the difficultly of the real problem you are solving.

For domains outside of physics and applied math, I think the dominating factor
is often the inherent trickiness of writing correct procedural code vs. the
ease of writing strongly typed functional code.

------
nostrademons
This is why everyone should study compilers and machine architecture in
college.

Anyway, it's interesting that he chose to label what he ended up with as
"Lisp". I would've stopped at assembly, eg. in LLVM IR:

    
    
      %result = icmp gt i8 %price, 100
      br i1 %result, label %Discount1, label %Discount2
      Discount1:
        ret i8 10
      Discount2:
        ret i8 5
    

The key idea here is that _underneath everything you tell the computer to do
is boolean logic and transistor circuits_. Yes, even Lisp S-exprs; it's not
really correct to say "Lisp has no syntax", it has a very simple syntax that
is trivially parseable. Even LLVM assembly is a translation layer, as is LLVM
itself; underneath it on my computer is an i86 processor, and underneath it in
my phone is an ARM-architecture Snapdragon.

Once you understand that, you realize that all of these languages and
frameworks and libraries and databases are just tools, and they exist for
_your_ convenience. They're there to let computers handle things that humans
are really bad at. For example, memorizing memory layouts really sucks; let a
computer map out your structs onto memory. Managing heap memory really sucks;
let a garbage collector do it. Managing register allocation really sucks; let
a compiler do it. Managing syntax kind of sucks; let a parser slap something
more friendly on top of it, or don't and use Lisp. Managing vtables kind of
sucks; let C++ or Java hide it behind a class, or don't and continue to use C.

Once you've gotten into this mindset, you're free from the religious wars that
surround technologies, because you realize it's all just tools that compile
down to machine code at the end. And you understand when a tool might be
useful, and when you could just as easily implement it yourself, and when it
once was useful but has since ceased to be.

~~~
tikhonj
That's one philosophy. Your code exists to be run by your computer.

Personally, I take a different one: the computer exists to run my code. LLVM,
x86, ARM... all just implementation details. Sometimes they're unavoidable,
but c'est la vie.

Ultimately, what I care about is _semantics_. I care about what my program
means--the logic it represents. After all, that's the whole point, the end
goal. The fact that it's running on a physical computer is just a detail,
albeit an important one.

A programming language is more about shaping my thoughts and forming my logic
than actually running. Choosing a programming language is incredibly important
--it affects what I can say, how I can say it and even how I _think_. And
that's the most important part.

~~~
millstone
The end goal of the web browser in which I'm typing this is not to represent
some piece of abstract logic, but to drive the physical hardware: to change
the color of pixels on my screen, to sense and react to my input. Attempt to
distill it to some piece of logic or mathematics, and you end up with
something useless, an absurdity.

The original task was "apply a seasonal rebate to our products," but none of
the programs actually accomplished this feat. They contained some logic which
might be useful in such a program, but none of them _applied_ anything. Logic
on its own is sterile.

~~~
theaeolist
I thought the end goal is to display the page. I would say that "to change the
color of pixels on my screen, to sense and react to my input" is a means to an
end, not "the end goal".

~~~
Tyr42
This was a really neat discussion to watch. Devotional vs Observational
semantics.

When I'm in my algorithms class and we have a code snippet to find a minimum
spanning tree, we don't even have some machine to compile it down to, but
because we have denoted some meaning to bit of the program, we can even prove
that the meaning of the entire program is to output the MST.

------
barrkel
Now show the same tree for a ruby block, a Java inner class, a C# lambda and
how they're all the same.

Except they're not.

Only the simplest ASTs are directly translatable. Language semantics differ
wildly when you get into higher level constructs. Not even Lisp is able to
help you, as that just changes the problem from one of syntactic
representation into one of library implementation.

~~~
theaeolist
That's for syntax. Also, for semantics, how do you translate C's pointer
arithmetic in Java?

~~~
jdiez17
All programming languages deal with pointers at some point or another, so it's
just a matter of finding the GCD.

At least that's what I think this is about, and Lisp is a good GCD.

------
Cort3z
Of course you don't care that much about which language to choose when you
just want to do a simple if statement. However when you want to do more
complex stuff, like answering a request on port 80 and compile a document that
you send back over port 80, making sure to encrypt it properly so that no
third party will get a hold of it, then it would be beneficial with some sort
of programming language.

The question should really be, why does the IT department care if he uses C or
Basic? And more over, why did he try to make it in C in the first place if he
knows the IT department prefer Basic? This is a case of unprofessional
behaviour by the author, not whether or not you need a language to express an
if statement. At that point he could just as well have written this is x86.
Who needs maintainability anyway?

------
xixixao
> Among other things, the C parser will look for curly braces, and the VB.NET
> parser will look for the eye soring Then keyword.

Here I would pick up the article and write this:

No matter which language I start with, the end result is always the same. So
maybe I could simply write out what is important for me:

    
    
      if price > 100
        10
      else
        5
    

And then I realized I was coding in CoffeeScript.

------
byuu
Sure, and when you write an expression more complex than a single ternary, you
start to see why Lisp is so uncommon in real-world usage.

It has a wonderful technical elegance, but the humans that have to write code
tend to not think in the same sense. After four or five brace levels it gets
very challenging to keep track of everything.

~~~
patricius
I think that can be said also of most mainstream languages, i.e., that more
complex expressions are less comprehensible. The same applies to increasing
levels of nesting. Lisp's syntax is so different that it just looks less
comprehensible than any language you're more familiar with.

------
wtracy
Well, you could edit machine code directly, or do the next best thing and
write in assembler:

    
    
        cmp eax, 100
        jle LESSTHAN
        mv 10, edx
        ret
      LESSTHAN:
        mv 5, edx
        ret
    

I doubt that's what the author had in mind, though.

~~~
sheetjs
I'm surprised the author didn't write a shorter C example:

    
    
        return price > 100 ? 10 : 5;

~~~
pmiller2
That produces a different AST than the if/else because it's an expression. :)

~~~
goldenkey
Every LISP statement is an expression too. So if you were trying to match
them, you'd use the ternary.

------
chattoraj
pg wrote about this years ago.

>If you understand how compilers work, what's really going on is not so much
that Lisp has a strange syntax as that Lisp has no syntax. You write programs
in the parse trees that get generated within the compiler when other languages
are parsed.

source:
[http://www.paulgraham.com/avg.html](http://www.paulgraham.com/avg.html)

~~~
jesstaa
It's as if lisp was originally designed to be an intermediate language for
computer generated parse trees....and not a language for people to read.

~~~
goldenkey
It's not as if..it is truly the case. That's why only nutters use LISP for
large projects. Who really wants to wrap every S-Expression in parenthesis?
Talk about painstaking and what an eye-sore. If only M-Expressions caught on,
LISP could be decent. But really, it's just making you write your program as a
data structure because that makes it easier for the compiler to process.

So...

Ruby: good for developers, bad for the JIT compiler (slow)

LISP: awful for developers, good for the compiler -> machine (fast)

Is the tradeoff worth it? Not at all. Most LISP intros start by convincing you
that you'll eventually get used to your code looking like a sack of
parenthesis. No thanks, I shouldn't need to get used to staring at
overburdened verbosity for the compilers' sake - build something better.
Wait..we have other languages that are fast and look nice. And many even
process into a well-formed AST. Okay, thank heavens.

~~~
aerique
I disagree that Lisp is awful for developers. To me and many others it looks
quite pleasant while the "other languages that look nice" actually look like a
needless mess of braces, brackets, asterisks, comma's, etc. etc.

Only Python comes close IMHO but has many other downsides.

~~~
goldenkey
Brackets, asterisks, and commas give array indexing, pointers, and the clean
separation of function arguments.

(incf (elt vector 2)) ..versus.. ++vector[2]

which one is more readable?

LISP is not to be taken seriously. It's an academic curiosity, and cute,
novel, not a language that needs continued zealots. It has no market
share..the reasons are always going to be the same. The language is esoteric.
I wouldn't program anything serious in JSON so why would I use LISP, where
every semantic is a list..not even a hashmap.

[http://imgs.xkcd.com/comics/lisp_cycles.png](http://imgs.xkcd.com/comics/lisp_cycles.png)

"These are your fathers' parenthesis"

~~~
zck
>(incf (elt vector 2)) ..versus.. ++vector[2]

One reason I like Lisp is that I don't have to think about operator
precedence.

~~~
goldenkey
Math expression: a(8b^2+1)+4bc(4b^2+1)

In LISP: (+ (* a (1+ (* 8 b b))) (* 4 b c (1+ (* 4 b b))))

Oh, that silly operator precedence, lets just jam our heads in a vice while we
unravel the nesting.

------
wildgift
Here's the code in either C or C#:

return ( (price > 100) ? 10 : 5);

Computer languages are for people. It should really be more like this:

    
    
        #
        # Description of what this does.
        #
        PRICE-THRESHOLD = 100
        LOWER-PRICE = 5
        UPPER-PRICE = 10
    
        IF PRICE > PRICE-THRESHOLD RETURN UPPER-PRICE
        ELSE RETURN LOWER-PRICE
    

Alternatively, use Excel:

    
    
        =IF( (price > 100), 10, 5 )
    

Excel is cryptic, but a lot of finance people understand it.

~~~
J_Darnley
With C it can be more like what you want. Stop using ?: if you don't like it.

    
    
        if (price > 100)
            return 10;
        else
            return 5;
    

Replace with more named variables if you want.

~~~
the_af
I'm going to guess wildgift was being sarcastic. COBOL syntax is so needlessly
verbose it interferes with the understanding of the actual formula. I contend
that

    
    
        return price > 100 ? 10 : 5; 
    

is way more readable.

------
mikro2nd
To quote Guy Steele, "All programming languages evolve until they become
Lisp."

(iirc)

~~~
juliangamble
This is a fascinating quote. It seems to be a combination of either:

* Greenspun's 10th rule of programming: "Any sufficiently complicated C or Fortran program contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of CommonLisp." [http://c2.com/cgi/wiki?GreenspunsTenthRuleOfProgramming](http://c2.com/cgi/wiki?GreenspunsTenthRuleOfProgramming)

* James Gosling quoting Guy Steele: "Lisp is a Black Hole: if you try to design something that's not Lisp, but like Lisp, you'll find that the gravitational forces on the design will suck it into the Black Hole, and it will become Lisp". [http://web.archive.org/web/20091201072950/http://blogs.sun.c...](http://web.archive.org/web/20091201072950/http://blogs.sun.com/jag/entry/the_black_hole_theory_of)

------
ww520
For simple business rules and logic, I found it useful to just use a table or
mini-spreadsheet to represent them. It has strict structure and it's simple to
understand and fill in. Business users love them.

------
ericHosick
We've been working on a programming language that is based on composition.
This basically leads to a hybrid data structure (not necessarily tree-
structured).

Here is an example (write out 1 2 4 8 16 32 on different lines):

    
    
       Application (
         using Library ( name "Vision.Console" )
         action ForEach (
           items 1 2 4 8 16 32
           action WriteLine ( text CurrentItem () )
         )
       )
    
    

Parts are upper case and properties are lower case. Each Part is a class 1
contained within a given framework.

------
girvo
I'm working on a toy programming language at the moment, and I was considering
using a LISP dialect of some sort as the IR to be compiled down to. Is this a
dumb idea? I had the same sort of epiphany that the OP had, but then I think
LLVM IR is a better choice. The only reason I like the LISP-as-IR idea, is
that if a programmer wants to get deep and optimise, the tooling can work with
lisp instead, which allows for some neat tricks I have in mind.

~~~
jaggederest
You're basically reontologizing the history of Lisp, which is that it was
originally S-expressions that were the intermediary language for
M-expressions, which were the human representation.

They never quite got around to making M-expressions though, people found
working in S-expressions to be pretty fine.

Dylan is sort of a compromise around this area though:

[http://en.wikipedia.org/wiki/Dylan_(programming_language)#Sy...](http://en.wikipedia.org/wiki/Dylan_\(programming_language\)#Syntax)

------
collyw
Someone influential (was it Joel) said that code gets read a lot more often
than it gets written.

I am not used to Lisp or VB.net but I do find the first two examples a lot
more readable.

(Seasoned Lispers, does reading Lisp get easier to read over time? As readable
as an imperative language?)

~~~
goldenkey
It's a sack of parenthesis anyway you slice it. Of course staring at anything,
including parenthesis, gets easier the more often you torture yourself. Just
like talking with a lisp, you get used to it...hence they call the language
LISP; painfully charming.

------
carlob
The overly eager optimizer in me was thinking:

    
    
        (price > 100) * 5 + 5;
    

yay! no branching!

~~~
Evgeniuz
(((price - 100) / abs(price - 100)) * 25 + 75) / 10

Here you go, simple integer math, no programming necessary :) That said, this
isn't optimisation, multiplication and division aren't intrinsically better
than branching.

~~~
carlob
x/abs(x) is really sign, which is something you can implement using bitwise
oprations.

Your solution fails when price == 100 as sibling pointed out.

------
sgt101
No one thinking that a contractor might have to maintain it in 5 years time?
No?

Ahhh _the fundamentals_!

~~~
DevKoala
My exact thought. Moreover, there might be other architectural reasons why he
was asked to implement the logic at the higher level. I can see what he is
getting at, but not his motives.

------
dschiptsov
Nice way to discover the _if_ special form. Now its time for short-
circuiting.)

------
dylandrop
Alright, that's one anecdote. But take a look at this one.

In Python:

a = 3 * 4 + 5

In Lisp:

(setf a (+ 5 (* 3 4)))

Now maybe it's just me, but balancing all those parentheses and thinking in
prefix notation gets a little hairy, especially if we introduce more math into
a program (think graphics or ML).

~~~
lispm

        3   7
        - + -
        4   8
    

Can't write that in Python. Looks like Python does not support even basic math
notation.

Lisp does not even attempt to do that.

We have to write

    
    
        (+ (/ 3 4)
           (/ 7 8))
    

or

    
    
        (+ 3/7 7/8)
    

Let's say we want to write a slightly more complicated expression in Python:

    
    
                   2 2 +-+    3+-+3+-------+2   3+-+2 3+-------+
               - 2b x \|3 log(\|a \|b x + a   + \|a   \|b x + a + a)
             + 
                 2 2 +-+    3+-+2 3+-------+
               4b x \|3 log(\|a   \|b x + a - a)
             + 
                          +-+3+-+2 3+-------+    +-+
                2 2     2\|3 \|a   \|b x + a + a\|3                  +-+3+-+3+-------+2
             12b x atan(----------------------------) + (12b x - 9a)\|3 \|a \|b x + a
                                     3a
          /
                2 2 +-+3+-+
             18a x \|3 \|a
    

Not possible. It does not know basic math format for roots, exponents, ...
Lisp also does not know it.

Balancing parentheses in Lisp is usually done with the help of an editor...

~~~
dylandrop
For the first part, it's still more intuitive (at least for me personally) to
write

a = 3/4 + 5/8

than

(setf a (+ (/ 3 4) (/ 7 8)))

and the primary problem that I have with the parentheses not closing them, but
logically seeing how expressions link together. Even if you can click on an
end paren and see the expression it closes off (as you can in most IDEs) it
would be easier just to not have the extra parentheses there in the first
place, so as to avoid the confusion.

It's really hard for me to even tell what you're trying to write for the
second part -- in Python or Lisp.

~~~
lispm

        (setf a (+ (/ 3 4) (/ 7 8)))
    

I have no problem writing or reading that.

Personally I like the parentheses a lot, since they allow me comfortable
editing operations for such expressions. Additionally it makes it easy to
computationally manipulate those expressions as data.

------
thomasfedb
If you expressing what you want the computer to do, and it understands you,
you are - by definition - using a language.

------
forgottenpaswrd
Oh man, so many people in the world need a better boss...

Without him, they will spend most of their lives on mindless debates sucking
their creative energy like a vampire blood.

