It was thus said that the Great Mouse once stated:
Take also, for example, Lisp. I've used Lisp. I even wrote a Lisp
engine. I love the language, even though I almost never use it. But
some of the mental patterns it has given me inform much of the code I
write regardless of language. I have seen it said that a language that
does not change the way you think about programming is not worth
knowing.
In my case, it wasn't knowing a language that changed how I think about
programming, but a book, _Thinking Forth_ by Leo Brodie. Think Agile
programming but in the mid-80s instead of the early 2000s. That it
described programming in Forth is immaterial---I've been able to apply the
lessons from that book to every language I've used since reading it.
The other book that changed how I program was _Writing Solid Code_ by
Steve Maguire (from Microsoft Press of all places). Think programming by
contract and single purpose functions [1].
The only languages that have had any influence on how I program are the
functional languages (summary: no globals, pass in state and avoid mutations
as much as possible)---it's not one single language.
People have remarked on the knowing of multiple
languages. I would say
it matters terribly what the languages in question are.
I think knowing the different families and how they work is important than
any individual language.
Knowing C,
JavaScript, Pascal, and awk is, for example, very very different from
knowing Lisp, Prolog, Objective-C, and TeX, even though each one hits
the same putative "knows four languages" tickbox on a hiring form.
True, and if I were hiring, I might worry that the programmer who knew
Lisp, Prolog, Objective-C and TeX might not want to work here where we deal
with C, C++ and Javascript as they're "not as nice to work with." But I
wouldn't discount them either.
I
draw a sharp distinction between "programming" and "programming in
$LANGUAGE", for any value of $LANGUAGE. Someone who knows the latter
may be able to get a job writing code in $LANGUAGE...but someone who
groks the former can pick up any language in relatively short order.
The bracketed note in the second paragraph of content on
http://www.catb.org/jargon/html/personality.html is exactly the sort of
thing I'm talking about here; ESR taught himself TeX by the simple
expedient of reading the TeXBook.
You mean not everybody does this?
One particular message seems to me to call for
individual response:
There are two major language families:
declarative and imperative.
[...] Declarative langauges are [...]. A few langauges under this
family:
Prolog
Agreed, though AIUI the presence of cuts weakens this somewhat.
(Caveat, I don't really grok Prolog; I may be misunderstanding.)
Cuts are a form of optimization (if I understand what they do). They just
cut down on the problem space.
make (and
yes, make is a declarative language)
Only, I would say, in its simplest forms. Every make implementation I
know of (including both at least one BSD variant and at least one
version of GNU make) stops looking very declarative when you have to do
anything at all complex.
I think those are poorly written Makefiles then. I've dived into GnuMake
rather deeply over the past year, and it's amazing how concise you can make
a Makefile, even for a large project. And the hardest part is really
getting the dependencies correct (but when you do, "make -j" really
flies on modern hardware).
SQL
I don't see SQL as declarative. I see it as imperative, with the
relational table as its primary data type. That the programmer doesn't
have to hand-hold the implementation in figuring out how to perform a
SELECT doesn't make SQL declarative any more than the code not
describing how to implement mapcar makes Lisp declarative.
I don't see it a imperative.
SELECT what FROM there WHERE ... ORDER-BY ...
You just describe what you want and how you want it ordered, unless I'm
missing something else. Granted, I don't work a lot with SQL (or with
stored procedures).
-spc
[1] The book used the realloc() function as the example---this function
can allocate and free memory, depending upon the parameters. In
fact, every possible combination of parameters is valid but will do
radically different things. It doesn't make testing harder (in this
case) but a logical misstep is harder to track down.
Better would be to have:
void *memory_alloc(size_t);
void *memory_grow(void *,size_t);
void *memory_shrink(void *,size_t);
void memory_free(void *);
Where you are explicit about what you are doing (and for
convenience, I can see memory_grow(NULL,x) being valid (allocate
memory) to mimic the reason realloc() is mostly used for.