Tcl
Someone wrote this copypasta:
Tcl is the best scripting language for the real but still productive hacker
(some of the fattest Schemes are not far), as long as you don't need a specific
library not easily available;
* Extremely small - whole syntax/grammar is described in 12 rules in a single
man page (Tcl(n)) of 150 lines and there's no reserved keyword.
* Homoiconic through strings (like almost every language with eval) but most
importantly, through "list-like" strings.
* Official man pages! No web garbage like cppreference nor lackluster
"minimalist" stuff like pydoc (compare pydoc print with man n puts, for
example).
* Kind of "unfashionable" language meaning basically no poz.
* At least two implementations with jimtcl being a quite thorough embedded one.
* One of the simplest if not the simplest interaction with C, letting you write
C plugins very easily (with critcl and swig to help).
* Comparable in speed to cpython, a bit slower than Perl 5 and Lua. Has a
WIP/dead LLVM compiler (tclquadcode) for a big speedup in the far and
uncertain future.
https://wiki.tcl-lang.org/page/Tcl+Performance for more.
* Cool type system that is superficially "everything is a string" (like sh)
but in reality "everything is a tagged union with on-the-fly conversion when
needed and a unique string representation". Allows for some very cool things
like editing dictionaries as lists or lists as strings and transparent
serialization (puts $mydict $chan <=> set mydict [read $chan]).
* Talking about types, multiprecision arithmetic is transparently handled,
allowing you to do expr {42 ** 1000} if you just want to.
* Very powerful introspection through info (mainly). Allows for stuff like
getting the name/body/arglist of a procedure, get all the registered
procedures, know if a variable exist, get information on the stack frames and
their content, etc...
Together with trace, you can write an internal debugger in few lines. See
https://wiki.tcl-lang.org/page/Full+program+trace+onwards for an example.
* Procedure arguments are passed by pointer with a copy-on-write system: don't
modify the argument and you don't get any memory copy. To you, it just looks
like regular passing by value.
* On the subject of simplicity, no need for an actual garbage collector,
reference counting is enough because you cannot make circular references.
* Modifying the procedure arguments is done via upvar: in Tcl, a variable
reference is just a name (string) with a relative stack frame number, quite
elegant considering the language's concepts.
* If you use at least the builtin extensions (thread, http, tdbc, tcltest,
msgcat) and the very basic tcllib/tclX/tclUdp/tklib packages, you're almost
set for life. Personally, I also recomment the very convenient tclreadline,
tdom, pipethread, tablelist and tclcurl.
Some more here: https://core.tcl-lang.org/jenglish/gutter/
* Channels is one of the cleanest I/O implementation I've ever used with some
cool features:
* Transformations allowing filters like deflate/zlib/gzip or TLS to be put on
a channel (see transchan for the API).
* Reflected aka virtual channels, to make your own channels. Basically like
glibc/BSD's unportable fopencookie/funopen or CL's gray streams.
* Centralize a lot of ioctl/fcntl shit and even more (like defining the EOF
char) in chan blocked/configure/pending.
* Integration with the event loop via chan event/postevent allows for a
nice callback oriented approach to sockets and pipes.
* Other third-party channel types include pty (expect), random, memory or
fifo (memchan).
* Builtin event loop (see after, vwait, socket -server and chan event)
for powerful and seamless concurrency/command scheduling.
* An elegant thread extension consisting of an interpreter per thread and no
raw access to other thread's memory. Comes with both simple (thread) and
performant (tsv) synchronization/communication facilities.
* Finally a sane, light and portable (even more with Tile) GUI toolkit: Tk.
* One of the fastest Unicode aware regex implementations, written by Henry
Spencer himself. Has its own greater-than-POSIX-ERE syntax called ARE, not as
complete as PCRE (lacking lookbehind constraints, most importantly), but
still great for an hybrid NFA/DFA engine.
cf https://github.com/mariomka/regex-benchmark/pull/44.
* uplevel (eval a script in a different stack frame) and tailcall (replace
the current procedure with another command) let you augment the language by
implementing control structures and keywords yourself. Inferior to CL's
synergy between unhygienic macros, "naked AST" style homoiconicity, symbols
as first-class objects, gensym and quasi-quoting, but still quite powerful.
* Safe interpreters let you do very fun things like config files in Tcl with
limited access to the machine and master interpreter.
* Recent versions (>= 8.5) really embraced FP with:
* Real lambdas (but not closures, these have to be emulated) through apply.
* Purer hash maps (dict) than ugly sticking-out-like-a-sore-thumb arrays.
* Lisp style prefix arithmetic (allowing for * 3 [+ 1 2] instead of
expr {3 * (1 + 2)}) including sane behaviour for more than two (reduce)
or zero (neutral element) arguments.
* Builtin map/filter (lmap) with 8.6.
See https://wiki.tcl-lang.org/page/Functional+Programming for more.
* Multiple more-or-less powerful OO systems (now based on the builtin TclOO):
[incr Tcl] for C++ style OO, XoTcl for a take on CLOS or Snit for something
Tk oriented.
* All of the above with the same advantage of CL: it does not enforce nor
preach a particular way of programming, unlike the ML family that comes with
the "everything is immutable" ball and chain that often gets in the way
instead of helping (because, big surprise, modifying data is often an
essential part of efficient and intuitive algorithms/programs while recursing
only makes sense when manipulating recursive data types; which arrays -
arguably THE modern big-cache-and-SIMD-CPU friendly structure - aren't).
* Biggest inconvenient are the near-death state of the language/community
(practical consequences: no LSP/SLIME equivalent, bugs accumulating, lack of
maintainted libraries) and the design warts/"features" (e.g. list <=> string
relation preventing possible differentiation between x, {x} and {{x}}).
As someone who knows a bit of CL, the language itself is less powerful
(e.g. macro vs uplevel, lambda vs apply) but the standard library quality is
miles ahead for a lot of common OS interfacing tasks (in CL, you need at
least UIOP, osicat, usocket, cl-ppcre to compare; and Ltk for Tk).
Basically, a mix of Lisp and Scheme that somehow managed to end up very good
and getting even better with time.
I could continue all day, but you should just try it. Some more talk about it:
* https://wiki.tcl-lang.org/page/What+is+Tcl
* https://wiki.tcl-lang.org/page/Tcl+Articles
* https://colin-macleod.blogspot.com/2020/10/why-im-tcl-ish.html
* https://yosefk.com/blog/i-cant-believe-im-praising-tcl.html
* http://antirez.com/articoli/tclmisunderstood.html
Where to begin:
* man n Tcl (or man 3tcl Tcl on some distros like Debian)
* https://wiki.tcl-lang.org/page/TCL+for+beginners
* https://wiki.tcl-lang.org/page/Tcl+Tutorial+Lesson+0
* https://wiki.tcl-lang.org/ for everything, this is where the Tcl community lives
* Rosetta Code for examples/exercises
My page: https://wiki.tcl-lang.org/page/q3cpma