there are many programming languages - thousands, in fact - and the number continues to grow. informally, "programming language" often refers to a combination of syntax, semantics, compiler implementations, available libraries, extensions, and the surrounding community. however, at its core, a programming language is defined by its syntax and semantics. these are the fundamental elements, as they allow a developer to precisely instruct a computer. everything else, such as tools and software ecosystems, emerges from this foundation. for this reason, syntax and semantics are the most critical factors when evaluating a programming language.
learning a language and mastering its intricacies requires significant investment. becoming highly proficient can take years. most people learn the languages that their company requires, those recommended to them, or ones that are popular due to effective marketing. once learned, these languages often become a lifelong preference, with developers rarely considering alternatives. language popularity is often influenced by the success of programs written in that language, but this is not necessarily indicative of the languages intrinsic qualities.
initial language choices are frequently arbitrary, but subsequent choices are often constrained by past experience. for example, after spending two weeks learning language x, a developer might opt to use it for a new project, rather than adopting language y, which would require additional time and effort to learn. over time, this dependency grows. why change tools when the current one, while imperfect, offers a familiar and somewhat predictable workflow?
there is also the intellectual challenge of solving problems in different languages. some tasks, easily solved in one language, may be more laborious in another. at times, developers find themselves grappling with problems that would not exist had a different tool been chosen. however, such issues are rarely obvious upfront, and finding solutions can be an engaging process.
the age of a language matters little. languages evolve, and an older design can endure if it is fundamentally strong. implementation quality is key. in practice, it is often more common to see popular but flawed languages gradually improved over time, rather than developers switching to languages built on superior foundations. for instance, complex and inconsistent syntaxes can persist simply because the language's ecosystem is well-established.
the term "readability" is often equated with ease of thought, but this perception is typically the result of extensive practice. reading code is an exercise in extracting information from visual patterns, which involves several cognitive processes. these include returning to the start of a line, recognizing distinct elements through whitespace, and associating sequences of characters with abstract concepts. unlike machines, humans face cognitive costs, and even small, repetitive mental tasks can accumulate into significant strain, reducing mental bandwidth over time.
notation allows varying degrees of flexibility, as different formatting choices can make code look distinct while preserving the same underlying structure. for example, whitespace is frequently optional, resulting in diverse formatting styles based on individual authors' preferences for whitespace usage.
while the following list does not go far beyond opinion, i only rate languages which i have used professionally for multiple days.
adhering to the "principle of least surprise". offers low-level control with a high degree of freedom, particularly in memory manipulation. most features map closely to their underlying implementation, though undefined and unspecified behavior varies across compilers. static typing, manual memory management, and direct access to memory allow for fine-grained control. highly optimized compilers exist for numerous platforms. however, it lacks modern features such as a module system, proper scope management, memory ownership semantics, and hygienic macros, making it both tedious and risky to use. despite its shortcomings, no superior alternative offers the same level of control and performance. there is also sc, which is c written with s-expressions.
its syntax excels for didactic purposes, merging the principle of least surprise with a syntactic elegance reminiscent of scheme. compiling directly to javascript, it offers a streamlined, decluttered alternative while remaining fully compatible with the javascript ecosystem, including node.js. coffeescript + javascript -> agility. its indentation-based syntax ensures readability and coherence. coffeescripts expressiveness comes from well-recognizable patterns derived from a minimal set of constructs, making it also ideal for configuration files - simpler and more intuitive than yaml, ini, json, or xml. perfect for code examples and algorithm learning, it is expressive and close to pseudocode.
schemes syntax and semantics prioritize pragmatic and autodidactic efficiency, making it one of the simplest languages to learn, parse, and translate.
certain r6rs features are questionable:
expressive but syntactically noisy (semicolons, though optional, are often used; the mix of square, curly, and round brackets adds to the clutter). it offers many syntactically distinct ways to achieve similar results (e.g., object literals, constructor functions, classes). asynchronous handling is convoluted, with async/await, promises, and continuation-passing styles often coexisting awkwardly. implicit type conversions, truthy/falsy values, and global variables (without var
) introduce potential bugs. despite these quirks, javascripts first-class functions evoke similarities to scheme.
package.json
and unnecessary asynchronous complexity.relatively simple, consistent, and expressive syntax, well-suited to object-oriented programming (everything is an object, which enforces simplicity). excels in one-liner scripts, command-line utilities, string processing, and metaprogramming. uses the nicer @
, @@
, and $
prefixes for instance, class, and global variables. provides p/pp
for debugging. designed as a successor to python, perl, and smalltalk. scope is marked by begin/end
rather than indentation, and ambiguously also with {}
where no additional brackets are required for additional method calls on the result. has ambiguous symbol syntax (:k => v
vs k: v
).
self
, underscore prefixes). not everything is an object, and printing is less elegant than in ruby. overall, pythons may be slightly less well-rounded than ruby.isset
checks for hash entries, with many implicit type conversions. often requires more comments than code. javascript can often provide more elegant solutions. see phpsadness for a detailed critique.if-fi
, variable substitution, quoting) are often meaningless or chaotic. posix shell is preferable for portability over bash/zsh.defun
, defvar
, progn
), with a less readable use of english words.1;
at the end of modules, makes perl esoteric. bash shares some of its oddities. try installing perl modules locally like node_modules. everything perl is praised for can usually be done better in ruby. despite this, the perl community remains strong, with numerous well-maintained modules.