

LFMs and LFSPs (Michael Vanier via PG) - aston
http://www.paulgraham.com/vanlfsp.html
A recent post by PG re: Arc spurred me to Google the term LFSP. Surprise, surprise, PG has an article on it on his own site.
======
pg
I'd forgotten how well written that was. It's better than 99% of the essays on
the web. And yet it was just an ordinary email, not intended for publication.

------
tuukkah
To get wider use of LFSPs, it would be important for more people to learn that
you _can_ and it's completely _reasonable_ to interface several programming
languages. You need to be comfortable with both languages to work on the
interface, but I find it surprising we didn't practice this at school at all.

To explicate what the article touches: Perhaps you really have to use Java
because of platform or workforce requirements, but it doesn't mean you have to
use 100% Java. More experienced developers can build some of the low-level
classes using C++ via JNI. They can also set up BeanShell or Jython for user
interface and test scripters.

~~~
nostrademons
Unfortunately, interfacing multiple languages is itself not a strategy for
LFM-people, because most of them can (or _believe_ they can) only fit one
language into their brains. There are costs to using more than one language on
a project. Managers frequently overestimate these costs, because they're the
ones who will look bad if their superior (or investor) looks at their
development process and say "Wow, this is chaos. No wonder you can't ship
software."

There does seem to be a loophole: you can use multiple languages if they all
start with the same buzzword. So, the same manager who balks at a
Python/C++/SQL solution because it uses too many languages has no problem
requiring that his developers learn Java, JavaScript, Java Server Faces, Java
Persistence Query Language, Java Expression Language, and the Java Standard
Tag Library, because they all start with "Java". Same goes with
XML/XSLT/XSLFO/XPath and derivatives.

Based on this observation, I suggest a renaming of all common hacker tools.
Python should be renamed "ParrotSnake", Ruby "ParrotGems", Lisp
"ParrotParens", SQL "ParrotQueries", JavaScript "Parrot in a Browser", HTML
"ParrotTags", Haskell "ParrotMonads", and so on. Then we could freely use any
of these on a project, because they're all the same language, duh. Of course,
the Parrot project itself should be canceled, because it'd defeat the purpose
to have them _actually_ running on a common VM. This is strictly a marketing
initiative.

~~~
tuukkah
Insightful! But does this in your opinion apply only to LFM-people - my
understanding is most LFSP-people don't see multiple languages as an option
either?

~~~
nostrademons
I dunno - most LFSP-people I know use multiple languages regularly, learn new
ones as a hobby, and their "preferred" LFSP is just the top of a long list of
skills. That's why we call them "smart people". ;-) Take a look at Programming
Reddit - most of the Haskell evangelists are also quite fluent in Python and C
and usually know Lisp, Ocaml, etc. too.

There do seem to be exceptions - Common Lisp in particular seems to be a LFSP
where many of its leading practitioners _only_ know Lisp. Smalltalk, too, but
to a lesser extent since all the commercial Smalltalk jobs morphed into
Objective C or Java jobs. But I don't really see Lisp as being at the top of
the blub hierarchy any more - there's been 20 years of progress since then and
some really interesting developments.

~~~
jey
" _Common Lisp in particular seems to be a LFSP where many of its leading
practitioners only know Lisp._ "

The hardcorest Lisp hacker I know wrote the chapter on C++ in the UNIX Haters
Handbook. He also wrote a C to Lisp compiler for the Symbolics Lisp Machines.
(And he works as a C++ programmer right now. :-))

UNIX Haters Handbook, published in the early 90s:
<http://research.microsoft.com/~daniel/uhh-download.html>

------
bayareaguy
Perfection is achieved, not when there is nothing more to add, but when there
is nothing left to take away.

\- Antoine de Saint-Exupery

------
uuilly
I totally understand people's complaints about C++. However I am never sure if
they are aware of some libraries that may concerns:

boost::function allows you to easily interchange function pointers, memeber
function pointers and function objects.

boost::lamda allows you to define transient functions at the call site. This
makes the old STL way more useful. To be sure the syntax can be a bit funky...

boost::bind pulls all the fun of boost::lamda and boost::function together.

With only the tiniest bit of discipline boost::shared_ptr's mean you never
have to worry about memory management again.

boost::any and QVariants (from the Qt Libraries) help you manage dynamic
typing. So an array of boost::any's can hold int's, char's, string's and
AnyTypeYouWant's all at the same time.

Everything I've mentioned is either in the standard or will be soon. Really
undergrad C++ is only the beginning. The STL and boost are almost a language
unto themseleves. I never use raw arrays or naked pointers anymore and it's
made development WAY faster while maintaining performance.

PG asked, why use a language where adaptors have to be built to get the
functionality of lisp rather than lisp itself (or something like that.) I see
his point but if the effort of getting lisp to work with C/C++ based code is
greater than the pain of using an LFM, why not make the best of an LFM?

Has anyone had the same experience? Or am I putting the "ass" in masses?

------
mynameishere
for (i = 0; i < N; i++)

Odd example to use. It's always annoying to re-type the same thing over and
over. But I recently went through a mountain of my Java code and replaced:

for (Object obj : list)

with

int size=list.size(); for (int index=0;index<size;index++)

I'm definitely very long suffering! It took a few hours but what you get with
abstractions is a loss of control over implementation. When you use the
tighter loop, the compiler turns everything (roughly) into this:

Iterator it=list.iterator(); //Which calls new ListItr(); for (it.hasNext()) {
Object next=it.next();

The abstraction has to do that because it doesn't know whether the list
(really, the java.util.Collection) is a LinkedList or an ArrayList or a Set.
If your loop itself is in a tight loop, it isn't hard to call it millions and
millions of times during program execution--which makes millions and millions
of unnecessary allocations and method calls. There is a loss of performance
which, at the end of the day, is more important than how much you enjoy your
job.

Of course, other languages would allow you to specify an implementation for a
given abstraction.

~~~
abstractbill
The replacements were for performance reasons, and it took a few hours to do.
Sounds like it might been more productive to replace only the occurrences the
profiler told you were causing problems...

------
bsaunder
For most of the article, I kept thinking, why hasn't he tried SWIG
(<http://www.swig.org>). Keep the needs-to-be-fast stuff in C/C++ (hopefully
with a well designed API), and code the fun, flexible, interactive stuff in
the LFSP of your choice (sorry apparently not all LFSP supported).

------
marketer
I'd be careful with pure research languages like ocaml. It has some advanced
features (polymorphic variants, functors, camlp4, etc. ) that even smart
people have a hard time understanding, because they are probably the subject
of someone's phd thesis. Also, LFSP's can be quirky: in Ocaml, for instance,
native integers are only 31 bits (using 32 bits requires the Int32 module,
which requires its own set of operations to use. Don't you love static type
checking?)

Bugs in LFSP compilers probably appear much more often compared to LFM
compilers.

~~~
tuukkah
Do we admit that smart people aren't infinitely smart? With LFSPs, I often get
the feeling I'm too stupid for a language, but in many ways it's better than
often feeling the language is too stupid for me.

Who cares whether you got 31 or 32 bits? The different operator names are
because Ocaml doesn't have operator overloading. For statically type-checked
and "overloaded" operators and functions, see type classes in Haskell.

------
brlewis
I think Joe Average and Joe Boss's perceptions of the advantages of LFMs are
completely bogus. The same solution implemented in an LFM and an LFSP will be
more readable in the LFSP.

~~~
aston
One of the features of LFSP's is that the code density is higher, which I'd
argue is a good way to make the code harder to read, not easier.

Here's an example in ruby:

    
    
     (1...10).each{ |x| print x }
    

Tell me, does the 10 print or not? You'll need a second glance plus a good
memory to answer that question.

Here's the same code in C++:

    
    
     for (int x = 1; x < 10; x++)
       cout << x;
    

Verbosity makes it easier for the non-you programmer to look at a random piece
of code and decipher it. You feel smarter for having written that Ruby code
(and the C++ is boring, I'll agree). But I'm gonna have to say the Ruby code
has less readability outright just because it's so dense.

~~~
pg
If (1...10) doesn't yield a list of numbers from 1 to 10 inclusive, that's a
bug in Ruby. The problem is not density. It's perfectly clear what this code
example _should_ mean.

~~~
jey
Sadly, no:

    
    
     irb(main):001:0> (1..10).max
     => 10
     irb(main):002:0> (1...10).max
     => 9
    

Ruby suffers from a bit of Perl-syndrome, and relies too much on magic syntax
and "conventions" created by library authors. It's a nice language and all,
but I still prefer Python over Ruby since Python is a simple, clean and
elegant language with just a small number of elegant concepts.

------
cheponis
I think this is why all TRUE wizards write in Assembly Language.

