Table of Contents for Programming Languages: a survey
Python
Because it is so well-known and well-liked, Python gets its own chapter.
See chapter on chapter on Python.
Go
Because it is so well-liked, Go (golang) gets its own chapter.
See chapter on chapter on Go.
Java
Because it is so well-known, Java gets its own chapter.
See chapter on Java.
Lua
Because it is so well-liked, Lua gets its own chapter.
See chapter on Lua.
PHP
Because it is so well-known, PHP gets its own chapter.
See chapter on chapter on PHP.
Javascript
Because it is so well-known, Javascript (js) gets its own chapter.
See chapter on chapter on Javascript.
Dart
A replacement for Javascript (ie meant to run clientside within websites).
Tutorials:
Overviews:
Features: method cascades, mixins, async/await, optional types, a rich core library, factory constructors, libraries, named parameters, lexical this, Futures, implicit interfaces, generics [1]
Opinions:
- "Dart itself is very simple to pick up basically as you write. It feels like the most generic 'algol family' language imaginable, in a good way." -- https://news.ycombinator.com/item?id=22454115
- "Dart is also a pleasant language, here are some pros and cons about language. pros: 1- Everything is object. (no more inconsistencies like Java primitives, null and generics) 2- It has very well designed generics and you can access generic type in run time. 3- Good Type inference. 4- Has powerful facilities for asynchronous programming.(eg: async await, coroutines ,...) 5- Not overall bad or complex type system. Compare to Golang or java dart's type system is vastly superior.osome cons: 1- Everything can be null (null is also object). 2- Lack of Union and algebraic data types. 3- Lack of python's like tuple.(eg: (1,'string')) 4- I personally dislike C-style type definition and mandatory semicolon (eg: int foo=23; rather than foo : int=23 ) " -- https://news.ycombinator.com/item?id=22455137
- "Generally I think that the dart language implementors should try harder not to copy language design fails from Java / C++, like null-pointers or half-baked enumeration types." -- [2]
Implementations:
unsound type system in v1 but not in v2
" You can design a type system that's simple, sound, and expressive. But you only get to pick two of those adjectives. Today, because programmers are delightfully spoiled by a wealth of nice, expressive type systems, I think they won't settle for simple and sound.
Dart tried simple and expressive, but the lack of soundness made tooling much harder and really confused users who felt like they were being sufficiently penitent in their type annotations but still got punished for the sins of unsoundness anyway — type failures that were only caught at runtime.
So I think if you're designing a type system for a language today, you end up pushed pretty hard towards "sound + expressive", but now you're talking about a really complex beast. " -- [3]
my note:
- https://dart.dev/guides/language/type-system#what-is-soundness says that Dart's type system is sound though
- i think it's a Dart v1 vs. Dart v2 difference: https://jaxenter.com/dart-2-0-strong-mode-135438.html
- but this says it's unsound (probably referring to v1): https://cs.au.dk/~amoeller/papers/undart/paper.pdf
- "Unless one is willing to make nontrivial extensions to thetype system (e.g. generic methods and local type inference)it is difficult to obtain full type safety, message safety, oreven gradual safety (as defined in Section 3.3) without caus-ing a significant increase in the number of static type warn-ings or runtime type errors in existing Dart code" -- http://cs.au.dk/~amoeller/papers/undart/paper.pdf
- generic methods and local type inference are both found in Dart v2, so i guess that's what they did
- "There are several causes of type unsoundness in Dart. First,initialization, assignment,and argument passing must satisfy anassignability check rather than a subtype check;the difference is that both subtypes and supertypes are allowed, but unrelated types are rejected. This means that the type system accepts code that might work, but rejects codethat will definitely not work (in checked mode — it might stillwork in production mode).This is of course not sound, but it does single out the cases where the types are obviouslywrong and hence require attention. Second, generic types are considered covariant (e.g.,List<Car>is a subtype ofList<Vehicle>iffCaris a subtype ofVehicle). This is notsound, but the trade-off is useful and meaningful, as known from arrays in Java. Third,function types require only assignability for the argumenttypes and for the return type,rather than the usual sound scheme where argument types are contravariant and returntypes covariant. Similarly, method overriding only requires assignability for argumentand return types" -- https://casa.au.dk/~amoeller/papers/fletch/journal.pdf
- but does the 'soundness' of Dart v2 include run-time type checking? "The Dart language is type safe: it uses a combination of static type checking and runtime checks to ensure that a variable’s value always matches the variable’s static type, sometimes referred to as sound typing" -- https://dart.dev/guides/language/type-system
- https://dart.dev/guides/language/specifications/DartLangSpec-v2.2.pdf claims the system is unsound: "The type system is unsound, due to the covariance of generic classes. This isa deliberate choice (and undoubtedly controversial). Experience has shown thatsound type rules for generics fly in the face of programmer intuition. It is easyfor tools to provide a sound type analysis if they choose, which may be usefulfor tasks like refactoring". Could this be out-of-date?
Haxe
Compiles to Actionscript, Python, Javascript, Java, PHP, C++, C#, or Flash and Neko bytecode.
See also Haxe's open implementation of the Flash API: http://www.openfl.org/ (discussion of Haxe in that context: https://news.ycombinator.com/item?id=9655437 ).
Haxe Features
Haxe Tutorials and intros
Haxe opinions
Haxe opinionated comparisons
- vs C#: "I made it a few days into rewriting before finding that although I like C#, I like Haxe more. In making the game I’d leveraged a bunch of core Haxe features like super enums and implicit typing and it was all getting trickier and trickier to implement by hand in C#." -- [4]
Have internals
C#
Because it is moderately well-known and moderately well-liked, C# (Csharp) gets its own chapter.
See chapter on chapter on C#.
Swift
Tutorials
Retrospectives
Swift Opinions
"Swift as a language is pretty great, however, the tooling and obj-c interop make it a pain in the ass....As well, it's far less 'scripty' than Obj-c. The type system in swift really leaves something to be desired in terms of typing types. The point of Obj-C was kind of to avoid writing the kinds of apps where a great type system would really shine, swift lets you build those kind of apps, but in my opinion most of the time we shouldn't be building them....ObjC? is a language that has everything you really really need, and left out the 1 thing you kinda wanted in exchange for leaving out the thousand 1 little things that everyone else wanted too. Like for example exceptions, sure they're there, but it's not idiomatic and when you program without them you realize what a crappy idea they were in practice. In day to day coding NSError is 1000x better than exceptions." -- https://news.ycombinator.com/item?id=9681090
"The problem I've found with Swift is the minute size of the standard library. This has forced a large amount of Swift libraries to make calls to Objective-C/Cocoa classes libraries which makes it very non-portable." -- https://news.ycombinator.com/item?id=9681408
- https://news.ycombinator.com/item?id=7835099
- https://docs.google.com/presentation/d/15MWKV5aVxX-SVNvcSwn2e5hvbsuS8Jkx5pA_Z2m22dw/pub#slide=id.g370b76a80_038
- "Swift looks terrific...At its core, the language is designed to eliminate bugs...Swift is not the simplest of languages. There are many keywords that make assertions about different things, and there a number of rather arcane rules about when arrays are copied or not copied, which initializers are allowed to call which other initializers, how protocols inherit from other protocols, and so on. But I don't blame the language designers for the level of complexity — each of the language's features feels like it was designed to address a genuine problem in software engineering, all the while balancing programmer productivity, performance, and code maintainability. Overall, as I was reading the Swift manual, I found myself mumbling "oh man" and "that's great" at all the things the Swift designers had done to help me write clean, bug-free code. I'll need to play around with Swift to know if it will be fast enough for all of my future application needs, but since it was designed by the same brain that brought us LLVM, I'm pretty optimistic about performance. There is one design choice in particular for which I would like to commend the language designers — no garbage collection. Instead, Swift uses automatic reference counting, which takes a little extra work on the part of the programmer (in order to prevent strong reference cycles). But the benefit accrues to the user, in the form of a hiccup-free software experience. I'm sure that Swift will be marketed in terms of its benefits to software developers, but I think the real beneficiaries are Mac and iOS users, whose lives are destined to get just a tiny bit more predictable, and that much more pleasant." [5]
- [6] also gives concrete examples of bugs that the author has faced in the past that Swift would have eliminated: "Renaming a function and forgetting to rename all of the overrides" (because Swift overrides must use the 'override' keyword), "After a subtle, undocumented change, a platform API no longer allows nil strings" (because Option types make explicit whether a variable is of nullable type), "I used a dictionary instead of a struct and mistyped the name of the key somewhere" (because in Swift "Structs are values and you can use them in collections" and "Swift has generics, so a function can ask for an array containing only a particular kind of struct")
- https://graydon2.dreamwidth.org/5785.html
- some nice things about Swift/contrasts of Swift compared to Rust: Swift has "a bunch of qualities that Rust lacks (the clang importer, reflection, a repl and playgrounds, runtime-dynamic generics, keyword arguments, cleanly-integrated reference-typed classes, user-extensible pattern matching, simplified local borrow-like alias control, compiler-supported ARC, generally much lower cognitive load) and an overall different area of focus (mostly user-facing, UI-centric app development, so far)." [7]
- "compiled...fast startup time...You don’t have NULL, you have Optional types. You can't throw without telling that your function throws, but not verbosely as Java's throws declaration, and there is nice syntactic sugar around it in the form of "try that and wrap in optional, in case of failure". You have pattern matching that works perfectly with Swift’s enums, which makes it very powerful. They also have type inference, that doesn't include method definition, but I guess it's fine." [8]
- "Why Swift isn’t my winner? It isn’t that easy or fun to use Swift in an editor that isn’t XCode...Swift also doesn’t have a static compilation yet, so you need to have the environment set up with Swift in order to use CLIs" [9]
- "While I have spent a lot of time with Xcode and Swift perhaps the ultimate test of how well it works is how much time you spend jumping into it again after being away from it for a while.
That did not work well for me. I cannot make sense of a lot of stuff I have done in the past. Swift is getting too complex. It is a nice language but it is developing some of the same problems as C++ and Haskell ironically. The complexity and strictness of the type system is getting in your face a little bit too often.
It is a double edged sword. When I began using Swift I loved how the strong typing caught many mistakes. But it was always with a mixed feeling, as battling the type system was a regular occurrence. Now it seems to have gotten worse especially when dealing with closures." -- https://news.ycombinator.com/item?id=24043427
- https://www.evanmiller.org/things-that-bother-me-about-swift.html
- https://www.evanmiller.org/swift-impressions.html
- "They certainly didn’t just make run-of-the mill choices for all language features. Some non-standard design choices they made (for better or for worse):
- Reference counting without any automated cycle-breaking
- Collections are value types (implemented somewhat efficiently by having copy-on-write collections)
- the Character type is closer to what ‘normal’ people think a character is (https://developer.apple.com/documentation/swift/character)
- consequently, string length is closer to what users who don’t know Unicode internals expect it to be.
- Arrays are ‘different’ (‘inherited’ from NSArray. See https://ridiculousfish.com/blog/posts/array.html)
- protocols are a bit like interfaces, but protocol conformance can retroactively be added to classes, even to ones you didn’t write or don’t have the source code of. " [10]
- "Swift Syntax is Poorly Suited for Functional Programming...The Smalltalk inspired syntax continued from Objective-C works very well with object-oriented programming, but is simply terrible for functional programming. When using functions as first class objects you don’t want to fiddle with making sure you got the right parameter names...When doing very functional style programming you want your functionality to be primarily in free functions. These are easier to pass around and use in a functional setting. But Swift ended up catering primarily to the OOP crowd, placing functionality primarily in methods." [11]
- "I was surprised by the statement since I use Swift mostly as a functional programming language. Sure you need to avoid classes and restrict yourself to value types but I enjoy the syntax. Immutability is guaranteed, closure syntax is not that clunky, the type system is great, extensions are amazing for namespacing and protocols / generics solve all my polymorphism needs. The language is huge though and getting bigger (which I don’t enjoy)." jdmoreira
- "I like Swift more than any other curly brace language, and I use it for functional programming. I have pure Swift apps in the App Store and continue to work on Swift projects. But compared to something like OCaml or Haskell, the syntax is just plain nasty for real fp. It feels clumsy and verbose - like wearing a pair of hob-nail boots for ballet dancing. However, I think they made a good trade off in terms of balancing readability, power and progressive disclosure." zepto
- Q: "In that Rust/Swift hybrid, what parts of Rust would you want added to Swift to make the hybrid? I read this article thinking Swift wouldn’t be a bad start." "In Swift I miss “everything is an expression”. I have mixed feelings about Swift’s special-casing of nullability and exceptions. Terser syntax is nice, but OTOH it’s more magical and less flexible/generalizable than Rust’s enums. Swift inherited from ObjC? multiple different ways of handling errors (boolean, NSError, exceptions) — that’d be an obvious candidate for unification if it could start from scratch. And if it was a “smaller Swift”, then I’d prefer a mark-and-sweep GC. With memory management Swift is neither here nor there: you need to be careful about reference cycles and understand lifetimes for bridging with FFI, but it doesn’t have a borrow checker to help." [12]
- "Maybe someone needs to write a Rust-- that cuts out most of the complexity." [13]
- "From what I’ve seen, that would be Swift..." [14]
- "Swift is a lovely language. It’s still missing good concurrency support, but they’re apparently working on something similar to Rust’s move-semantics. I do still feel like it’s not something I can use in cross-platform code yet." [15]
" ... why academics and data programmers are never going to use Swift:
Python:
import time
for it in range(15):
start = time.time()
Swift:
import Foundation
for it in 0..<15 {
let start = CFAbsoluteTimeGetCurrent()
This is why people like Python:
- import time: clearly we are importing a 'time' library and then we clearly see where we use it two lines later
- range(15): clearly this is referring to a range of numbers up to 15
- start = time.time(): doesnt need any explanation
This is why academics and non-software engineers will never use Swift:
- import Foundation: huh? Foundation?
- for it in 0..<15 {: okay, not bad, I'm guessing '..<' creates a range of numbers?
- let start = CFAbsoluteTimeGetCurrent?(): okay i guess we need to prepend variables with 'let'? TimeGetCurrent? makes sense but wtf is CFAbsolute? Also where does this function even come from? (probably Foundation? but how to know that without a specially-configured IDE?) ... " [16]
- "Are you sure? What stops Swift with its beautiful syntax and safe optionals from becoming a systems language?" -- [17]
- "As someone who has actually tried writing a kernel in Swift, the issue is purely the runtime. While you can technically build a module without it needing to link to external Swift standard library binaries, the second you try and do anything with an array or optionals, you suddenly need to link in a 15MB behemoth that requires SIMD to even compile (at least on x64 and arm64). Porting this to bare metal is possible (and some have done it for a few microcontrollers) but its a pain in the ass. I do love Swift and would use it for systems stuff in a heartbeat if I could, but there are also some downsides that make it pretty awkward for systems. The performance isn't always the best but it's (generally) very clear and ergonomic."
- "Perhaps not that that much. Swift’s arrays are refcounted. And you can’t store an array on the stack. Classes are refcounted too, but you could avoid them. It also has a bit of a runtime, and you don’t know when it will take locks or allocate (though there is work to tag functions so they can’t do either)."
- A Pleasing Symmetry in Rust: Appreciating how Rust enum variants are mirrors of its kinds of structs
- "Swift kinda at least is in the right ballpark I think, but there’s a big issue of platform comparability: if I understand correctly, a lot of weight is pulled by MacOS? specific foundation library. And it also has quite a bit more complex type system than I think is optimal." -- [18]
- https://flak.tedunangst.com/post/an-aborted-experiment-with-server-swift
Swift gotchas
- For..in gives you the elements of the collection by value, not by reference [19]
Swift internals and implementations
ABI:
https://download.swift.org/docs/assets/generics.pdf
Ruby
Retrospectives:
History:
" Ruby was conceived on February 24, 1993. In a 1999 post to the ruby-talk mailing list, Ruby author Yukihiro Matsumoto describes some of his early ideas about the language:[11]
I was talking with my colleague about the possibility of an object-oriented scripting language. I knew Perl (Perl4, not Perl5), but I didn't like it really, because it had the smell of a toy language (it still has). The object-oriented language seemed very promising. I knew Python then. But I didn't like it, because I didn't think it was a true object-oriented language — OO features appeared to be add-on to the language. As a language maniac and OO fan for 15 years, I really wanted a genuine object-oriented, easy-to-use scripting language. I looked for but couldn't find one. So I decided to make it.
Matsumoto describes the design of Ruby as being like a simple Lisp language at its core, with an object system like that of Smalltalk, blocks inspired by higher-order functions, and practical utility like that of Perl.[12] " -- http://en.wikipedia.org/wiki/Ruby_%28programming_language%29#History
Tours and tutorials:
Respected exemplar code:
Gotchas:
Tools:
In-depth:
Internals:
Variants:
Ruby features
Ruby Opinions
- "Ruby comes closest to realizing the "promise" of dynamic languages. That is, it's fast to build with when prototyping, flexible when refactoring, reasonably fast enough and not so memory hungry that it can't handle "web scale". Obviously there are languages that are better in each of these areas, but few that combine so many as well as Ruby. In other words, if you know that you'll be working in a problem domain (e.g. high concurrency) where specific advantages of some other language (e.g. Go/Erlang) are likely to be needed, use that language. If you're just building something, then Ruby's a fine place to start." -- https://news.ycombinator.com/item?id=10791366
- "It's still one of the most terse and transparent languages around, plus there are tons of jobs for working with it. I quite like Go, Python, TypeScript?, etc but Ruby is in a league of its own when it comes to short and sweet. It's a pleasure to write. " -- https://news.ycombinator.com/item?id=10791311
- "nothing else approaches it in terms of linguistic flexibility" -- https://news.ycombinator.com/item?id=10791658
" zem 1 day ago
yielding in a method without an explicit block parameter is actually my favourite design decision in all of ruby. it basically means every method gets a "free" optional block passable to it at call time, which in turn means that the language highly encourages (syntactically) code designs where a method implements some pattern and then yields to the calling code to fill in the details. compare ruby's "File#open" with common lisp's "with-open-file" - it was just the natural thing to do in ruby, versus having to implement something specifically for the open-file case in lisp.
reply
rat87 13 hours ago
I'm a guy who hasn't written that much ruby, I'm mostly writing python these days but I understand a lot of the concepts have written a bit of ruby and wish that some python things could be more like ruby.
Also I'm a guy who took a Smalltalk class taught by a passionate teacher back when I was getting my degree.
Smalltalk is one of the main parents of ruby. It's less practical then ruby in many ways but its more pure/simpler.
To me ruby's blocks/yield is one of the ugliest of parts of ruby. In Smalltalk just about everything is objects and messages. In Smalltalk Blocks are just special syntax for BlockClosure? objects that you evaluate by sending the 'value' method on them and they don't have to be passed at the end, you can pass multiple blocks(if you want ideas of why you might want to do this see some of the c# linq overloads: https://msdn.microsoft.com/en-us/library/system.collections.... (or some thread/future like thing with a run action and an exception callback) although I admit many of them can be done with an extra map function.
Ruby Blocks aren't objects, yield is not a method, it's harder to assign/store closure to variables and pass them around.
I may be wrong but I was under the impression that blocks are the way they are because they are a speed hack, the original ruby being a simple interpreter and blocks allowed the common pattern of defining and passing a closure to the method calling the closure without overhead of allocating/initializing/gc a block closure object.
Other objections ruby doesn't seem to be a language that the number of arguments in the function declaration doesn't bear resemblance to the number of arguments you can pass ala javascript I don't see why blocks should be special, I don't want to glance at the body of the function to see if it expects a block or not.
Also if you want to overload on block_given? you can use a named/default argument at the end defaulting to nil.
reply
masklinn 1 day ago
> it was just the natural thing to do in ruby, versus having to implement something specifically for the open-file case in lisp.
Uh what?
1. File#open is a special implementation, the canonical opening of a file is File#new
2. with-open-file is just a wrapper macro around unwind-protect/open/close
reply
zem 1 day ago
i meant that it's a natural thing to do in ruby to implement patterns like open/yield/close or decorate/sort/undecorate as methods that yield to a block. with-open-file was probably a bad example, but from experience it does change the feel of the language when you have to explicitly specify a closure argument versus when you just expect that your method should allow for a block to be attached to the method call. i'm not saying that these things aren't possible in other languages, just that ruby's "free" block makes them a culturally default thing to do.
reply "
- expressive language...mature libraries...Tests are baked into the community core more than any other language I’ve ever used.... Ruby is a pure OOP language, so most of the code will share the same API style — classes, no matter which libraries you’ll choose. The community is powerful as well -Ruby devs seem to contribute code to already-made libraries instead of writing their own library each time..." [23]
- is too slow and takes too long to startup a Rails app on a server [24]
- "The difference between symbols and strings as hashmap keys is a footgun that opens up endless bugs for the type of glue code that you'd often be writing in Ruby." [25]
- "I've found Ruby to be far more "learnable", in that once I learn how something works in Ruby, it will work that way in most every situation going forward, whereas Python has a lot of caveats to its functionality. This might just be due to my use cases, but the Ruby documentation is 100x more useful for getting me from point A to point B than anything I've seen from Python's docs. I still use Python daily, since its so ubiquitous, I just find myself having a difficult time using it for anything remotely complicated without a lot of extra research. " [26]
- vs Elixir: "I’m mostly an Elixir dev, but since the Erlang Runtime System sucks at POSIX (bad at pipelines, bad at exit codes, bad at trapping signals, etc.) I personally switch to Ruby when I need a glue language." [27]
- vs. Elixir "I found that I was coding almost exclusively in a functional style, in Ruby (because it was easier code to test and it seemed to produce less bugs/fewer mental-model problems), then realized I was still missing out on the guarantees that Elixir gives you, then I thought, what's the point in staying when I could get guarantees that eliminated entire classes of bugs for free? Having done Elixir for a few years now, I RARELY have to go into "debugging mode", I've never even had to fire up Elixir's version of "pry", and my tests have caught all but a few bugs. All my logic lives in sensible locations. It's pretty nice! At least for web dev...That, plus Elixir was literally 5 to 10x faster at a sampling of tasks I threw at both (but this was a few years ago)" [28]
- vs. Elixir "I had the same epiphany; the hard-won "best practices" I had discovered in Ruby/Rails ended up looking a lot like second-rate functional programming. Having spent the last year with Elixir in production, I don't plan to go back. Things like Ecto, ExUnit?, error handling using "with", Phoenix Presence, domain modeling using Phoenix Contexts, Absinthe for GraphQL? have made programming a joy. " [29]
- "Anecdotally, since I got away from Ruby, working on software became way more productive and tolerable. Maybe it was something with the corner of the Ruby world I fell into, but the syntax sugar options and “cleverness” that enabled was maddening to deal with, and permeated that crowd. Code bases with mixed styles are a thing in any language, but the Ruby-ists around me found a way to make one project look like half a dozen languages were involved." [30]
- "Interesting, I'd say the opposite. In a Rails app that was written consistently with the styles and APIs documented in the Rails docs I have never been more productive. In other micro-framework type environments, regardless of the language, Ruby/Sinatra, Python/Flask, Javascript/Express. Most codebases I've encountered are a mess of inconsistencies introduced by various developers over the years."
- " Rails is not vanilla Ruby. And web apps are not the only software that needs to be written. I moved on from Ruby land right as AWS was blowing up, and admitted I have never worked in Rails. "
- https://madhadron.com/posts/2013-02-25-a-criticism-of-ruby.html
- https://news.ycombinator.com/item?id=29272682
- "The seamless blend of OO, functional, and imperative programming is beautiful. It can be dense without being obscure. irb and pry make it easy to explore code and data. The syntax is mostly conventional and easy to learn. The standard libraries are well designed, and have consistent interfaces. The documentation is concise and easy to scan. I won't say its "The Best", but of the dynamic, interpreted languages I know, Ruby is the most fun to use, and it starts with the clean, well-considered design right at its core. " [31]
" I think in hindsight it would have been helpful for Ruby if it had done something like square braces instead of brackets for hash literals, or not allowed brackets for blocks. The most ambiguous syntax all involves hash literals vs blocks… this adds to that cognitive load." -- [32]
- https://threadreaderapp.com/thread/1365014133180141578.html
- https://lobste.rs/s/75gpxo/long_rant_about_ruby_its_value_its
- "Obviously, I don't know what exactly @yukihiro_matz thought on all design stages, but my guess is it all started with Enumerable: the amount of "design elements" which made `for` obsolete is surprisingly low, but their mix is "just right"."
- "I appreciate the author mentioning that Ruby’s sort of “phrase-oriented programming” seems to have stemmed from how Enumerable is built, because that has been my gut feeling on why I like Ruby so much as well. It’s nice not having to write for loops and the brevity of Ruby’s syntax makes applying what are essentially lambdas to common list operations so simple." -- [33]
- " The instance_exec method allows for succinct DSLs whose syntax couldn’t be easily copied in other languages like Python. Basically, it allows you to evaluate blocks as if they were running in the scope of an arbitrary object’s methods — or to put it in Rubyist terms, it allows you to execute blocks with an arbitrary receiver. For (a completely contrived) example, in Python you might write: conf = Library.config_object() conf.config_file("foo.txt") conf.worker_processes(2) worker = Library.worker(conf) Whereas a Ruby library might read: worker = Library.worker do config_file "foo.txt" worker_processes 2 end The interior of the Ruby block defining the worker feels in a certain sense like a DSL; these methods are not in global scope: they’re special methods that are accessible inside the block, running on an anonymous object. It’s sort of like having a domain-specific language with new keywords — config_file and worker_processes — that elegantly composes with standard Ruby. Of course, really all it means is you can leave out repeated references to conf, since Library.worker makes everything run as if it’s in the scope of some method on conf (and Ruby has implicit self inside method calls, so you can write config_file instead of self.config_file). But ergonomically it can feel nice. It’s the same number of lines, but much less significant text. " -- [34]
- "The “everything is an object” is quite nice because it’s easy to use the language to introspect the language. You don’t need to reach for documentation if you can get your project into irb. But, the metaprogramming (all I see are footguns), the performance, the loosey-goosey way that the language breaks in minor versions (requiring new version managers). " -- [35]
- "...I do not even get why people hate Ruby so much...Ruby is a flawed language (I especially dislike the lack of real namespaces) but the hate it gets is often not based in reality." -- https://news.ycombinator.com/item?id=33797713
Type system
Type annotations:
" This is anecdotal, but my experience was that Ruby was fashionable in the wrong kind of ways. For example... Ruby doesn't have primitive data types. Everything, including strings, are just objects. This level of purity is quite nice and "cleaner" in a conceptual sense. Until you encounter a large codebase with hundreds of monkey patches. Or, something I saw a lot, the extending of "base" data types such as String. I must admit that my memory is a little hazy here, but I remember that it was impossible to find language tooling that allowed me to "jump to definition" of anything I encountered. Ruby was so free-form with so much ambiguity that at the time it just didn't exist. I'm sure this has been resolved by now. In Python we had "Jedi" and other tools that worked really well for this purpose. You'd be browsing a Ruby codebase, see `some_str.foo`, and wonder: 1) Is foo a method or a property? In Ruby a function call doesn't need parenthesis if it takes no arguments. 2) Where is foo? I don't remember it being part of the standard library. Where is it defined? 3) If I do find foo, did something else monkey patch it? How would I know? 4) If I need to pass an argument into foo, should I factor it out of String? At what point am I overloading a base class like String with too much functionality? These are very real questions and the answers are important. Come across enough of these scenarios (remember this is just one example w/ Ruby) and you eventually give up trying to understand the codebase at that level. Everything becomes a black box, everything is magic. Do these footguns exist in Python? Sort of. You can't extend primitive types and monkey patching doesn't fit so cleanly into a normal program (think of it as "friction"). There was less ambiguity in Python's syntax. And the language community promoted a list of idioms which was helpful for discouraging bad practices. These things may seem subtle but they made a pretty big difference at the time. " -- [36]
Opinionated comparisons
- Ruby vs. Crystal: "I, personally, find relatively heavy metaprogramming to be super valuable and to make me significantly more productive with my tools. I live on `instance_eval` and `send`, and Crystal's flavor of compile-time macros doesn't do it for me." -- [37]
- vs Python: " Having done both Ruby and Python, I confirm that they are pretty similar languages, both performance wide and syntax wise."
- vs Python: "Ruby syntax has a higher learning curve, making it harder on beginners."
- vs Elixir: "I think it's mostly the REPL that allows for quickly spiking out things, with quick feedback. Elixir has a similar experience, but less of the warts you get with Ruby (like monkeypatching)." [38]
- vs Go: "Ruby is faster to write than Go, and the REPL is a big part of that." [39]
- vs Python: "Warning: opionion from someone who primarily used python a long time ago Ruby's design is a lot more consistent/predictable/ergonomic than python. the ruby standard library is honestly amazing (see: https://ruby-doc.org/core-2.7.2/Enumerable.html) Everything is an object, methods take blocks where that makes sense. stuff just feels well thought out and generally when I learn something new about ruby I think 'wow that makes sense' and not 'why would you do it like that'. There also seems to be much much less churn from a tooling perspective. Learn how gems/bundler works and you're set. Also, ruby can be a (in my experience) superior replacement for awk. Brief example, -n is loop over current line as $_, -l is clean up line endings cat .zsh_history
ruby -nle 'BEGIN{$x=[]}; $x << $_.encode("UTF-8", invalid: :replace, replace: ""); END{$x.sort_by{ _1.count(" | ") }}' |
I was trying to find some longer pipelines from my command history. encode is stripping out a bunch of invalid utf-8, otherwise it would have just been $x<<$_ or, pick a random line from stdin: ls ruby -e 'puts ARGF.to_a.sample' |
" [40]
- vs Python: "...I learned Python after learning Ruby (and Javascript) and had a hard time with Python namely with scoping and lambdas. I think if you care a lot about the philosophy behind Python (have one obvious way to do things, explicit over implicit) and the syntax, then you might have some difficulties picking up Ruby right away. With that said, I think it's a very enjoyable language; Rails is still a very enjoyable ecosystem; and it works well for scripting especially if you're trying to write organized shell scripts. " [41]
- vs Python: "Both languages have their strengths and weaknesses. I have a Ruby background and have been learning Python more recently. After years of "artisinal" Ruby with heaps of unnecessary metaprogramming magic Python seems nicer to me, but I'm senior enough to be aware of my perceptions not necessarily being reality." [42]
- vs Python: "IMO Python has more libraries, more developers (people who might want to work on your project with you), and a more simple and intuitive syntax (easier to onboard people). Ruby is a fairly quirky language, eg functions aren't first-class values. " [43]
- vs Python: "I once heard someone talk about how they preferred Python as a language more, because it was simpler, but enjoyed actually programming in Ruby more, even thought it was more complex, and they value simplicity. The reason is that all of that nasty ugly stuff Ruby lets you do makes you be able to make extremely nice APIs. Things you couldn't do, or just folks don't do, in Python. And therefore they ended up liking using Ruby more in practice." [44]
- vs Python: https://softwaredoug.com/blog/2021/11/12/ruby-vs-python-for-loop.html
- https://solnic.codes/2022/02/02/rails-is-not-written-in-ruby/
Ruby variants and implementations
- https://mruby.org/ "mruby is the lightweight implementation of the Ruby language complying with part of the ISO standard. mruby can be linked and embedded within your application."
- https://github.com/artichoke/artichoke
- https://github.com/chrisseaton/rhizome
- https://dragonruby.org/ "DragonRuby? is a zero dependency, cross platform, Ruby runtime built on top of mRuby, libSDL, and LLVM. Write Ruby on any OS and deploy to PC, Mac, Linux, iOS, Android, Raspberry Pi, WASM, Nintendo Switch, Sony Playstation, and Microsoft Xbox."
- https://www.jruby.org/
- "This reminds me of when people try to make a new Ruby implementation. They get the basics down and think "this isn't so bad! I can do this!". Fast forward a few months and they're stuck on some nasty little edge case around eval and method_missing that they need to run Rails. Or some weird aspect of C extensions." [45]
- https://natalie-lang.org/
- https://developers.redhat.com/articles/2023/10/09/mir-based-jit-prototype-ruby
- https://developers.redhat.com/articles/2022/11/22/how-i-developed-faster-ruby-interpreter
Ruby type systems
Ruby internals
Ruby links
Less popular imperative, MM, OOP languages
Perl
note: since most of the following was written, Perl 6 was renamed Raku and is now considered a separate language.
Pros:
- "There's more than one way to do it" (TMTOWTDI)
- "Easy things should be easy and hard things should be possible"
- [46]:
- "multi-paradigm, enabling elegant object-oriented, functional, procedural, and concurrent programming
- Serves as a great glue language, allowing for easy calling of C/C++ (using NativeCall?) and staying compatible with Perl 5 (via Inline::Perl5).
- Provides composable constructs for working with asynchronous data and parallel computations
- Dramatically reforms and sets a new standard in regex syntax, which scales up to full grammars – powerful enough to parse Perl 6 itself
- Has outstanding Unicode support, with strings working at grapheme level
- Values lexical scoping and encapsulation, enabling easy refactoring
- Is extensible through meta-object programming, user-defined operators, and traits"
"core values of Perl: expressiveness, getting the job done, taking influences from natural language, and pushing the boundaries of language design" -- [47]
Perl 6 design docs:
Tours and tutorials and lists of libraries:
Books:
Perl 6 links:
Perl6 design process
Perl opinions
Some say the choice of a '$' prefix for (singular) variables is ugly, although useful [48].
Comparisons
- "Perl suffers from having too many magical operators that makes it hard to reason about a snippet of code. I feel Python strikes the right balance." [50]
Retrospectives
- "I lovingly reused features from many languages. (I suppose a Modernist would say I stole the features, since Modernists are hung up about originality.) Whatever the verb you choose, I've done it over the course of the years from C, sh, csh, grep, sed, awk, Fortran, COBOL, PL/I, BASIC-PLUS, SNOBOL, Lisp, Ada, C++, and Python. To name a few. To the extent that Perl rules rather than sucks, it's because the various features of these languages ruled rather than sucked." -- http://www.wall.org/~larry/pm.html
- "Perl is, by and large, a digested and simplified version of Unix. Perl is the Cliff Notes of Unix." -- http://www.wall.org/~larry/pm.html
- http://www.softpanorama.org/People/Wall/index.shtml
Perl Jokes
Perl examples
" sub Σ(@array_to_sum) { return [+] @array_to_sum; } say Σ (1,2,3,4); # It will display 10 "
[51]
Smalltalk
Because of its importance as an exemplar of a style of computer language, Smalltalk gets its own chapter.
See chapter on Smalltalk.
Raku / Perl 6
https://docs.raku.org/language https://docs.raku.org/
Opinions:
Self
Tutorials:
Retrospectives:
Misc self:
- "The Self programming language additionally uses method dispatch for "instance" or "local" variables, as they are only exposed via reader and writer methods, demanding the better technique of polymorphic inline caching" -- [52]
Links:
Io
" Io is a small, prototype-based programming language. The ideas in Io are mostly inspired by Smalltalk (all values are objects), Self (prototype-based), NewtonScript? (differential inheritance), Act1 (actors and futures for concurrency), LISP (code is a runtime inspectable/modifiable tree) and Lua (small, embeddable)."
Whitepaper and intro/guide:
Pros:
- simple
- tiny
- embeddable
- "highly dynamic and introspective"
- coroutines and async i/o
- all values are objects
- late binding
- all code is expressions
- "code is a runtime inspectable / modifiable tree"
- "all expressions are made up of dynamic message sends"
- "Execution contexts themselves are objects"
- "activatable objects such as methods/blocks and functions are unified into blocks with assignable scope"
Other attributes:
Influenced by: Smalltalk, Self, NewtonScript?, Ac1, Lisp, Lua
Links:
Newspeak
https://newspeaklanguage.org/
Nemerle
.NET language
Papers:
Nim
https://nim-lang.org/
Features:
- "High-performance garbage-collected language"
- "Compiles to C, C++ or JavaScript?"
- "compile-time metaprogramming features such as syntactic macros and term rewriting macros." * "Iterators are supported and can be used as first class entities[9 in the language as can functions, these features allow for functional programming to be used. Object-oriented programming is supported by inheritance and multiple dispatch. Functions can be generic and can also be overloaded, generics are further enhanced by the support for type classes. Operator overloading is also supported.[9] Nim includes automatic garbage collection based on deferred reference counting with cycle detection" [53]
- static typing
- type inference
Opinionated comparisons:
- "It is all that Python was, plus unbelievable speed, compiling to shippable binaries, and some other cool language features that admittedly, are still beyond my scope of abilities. Still quite lacking in libraries compared to Python, but after a few attempts (perhaps halfhearted), I never felt "Go" was a suitable replacement." [54]
- "+1 for Nim: it writes like Python and runs like C." [55]
Tutorials:
OOP libraries and frameworks in other languages
Common Lisp Object System (CLOS) Meta Object Protocol (MOP)
Lisp Flavors
Influenced CLOS.
https://en.wikipedia.org/wiki/Flavors_%28programming_language%29
Perl
Fantom
---
Kotlin
Tutorials:
Features:
Retrospectives:
Opinions:
- https://medium.com/@octskyward/why-kotlin-is-my-next-programming-language-c25c001e26e3
- http://steve-yegge.blogspot.com/2017/05/why-kotlin-is-better-than-whatever-dumb.html
- "Actually Kotlin is just Scala dumbed down by taking out the most powerful and interesting features like higher kinds, implicits, monads or macros. Which makes it just a Java 8 with a bit nicer syntax." * " I am a pretty big fan, but for non-Android contexts I still like Scala better for a ton of reasons. I wrote a large Kotlin lib[https://github.com/cretz/asmble the other day and documented a few annoyances[56] I had with it and the devs were very responsive (though non-devs seemed to pick apart maybe one or two of bullet points to dismiss the entire critique). In the future I would use Kotlin for any Android need (obviously) and any time where I wanted to be lighter weight than Scala. As for native/JS use, I am waiting on the multiplatform story to materialize more before I have a strong opinion, but I would still go with Scala for how easy it is to develop multiplatform libs/progs w/ JVM/native/JS where I can easily have platform specific pieces. Kotlin is almost there[57], but not quite yet."
- https://gist.github.com/cretz/2a49514b18914ef09b7c518db6db116c
- Q: "Just curious what you dislike about Kotlin’s design? It seems like you make two points: that Kotlin can’t escape Java and, separately, that it’s poorly designed. I agree with the former, but in light of the former, I find Kotlin to be pretty well-designed. They fixed Java’s horrible nullness issues and even kludged in free functions to the JVM, which is neat. Data classes are a band-aid, but still help for the 80% of cases where they can apply. Same with sealed classes (I’d much prefer pattern matching akin to Rust, Swift, OCaml)." A: "My biggest issue is that everything feels like a kluge. Null tracking at the type level is fine, but they didn’t really go far enough with the syntax to make it as useful as it could have been- rust does better here by allowing you to lift values from an error context inside of a function. The language tries to push you toward immutability with val and var, but it’s superficial because you’re getting immutable references to largely mutable data structures without even getting a convenient deep copy. Extension methods are a fine way of adding capabilities to an object, but you can’t use them to fulfill an interface ala go, or outright extend a class with an interface implementation ala Haskell typeclasses, so you’re left with basically a pile of functions that swap an explicit argument for a this reference, and in the process you are conceptually adding a lot of complexity to the interface of an object with no good associated abstraction mechanism to be explicit about it. Even the nature of the language as a cross platform language that can target jvm, llvm, and web asm seems fundamentally flawed because in practice the language itself seems to lack enough of a stand alone ecosystem to ever be viable when it’s not being backed up by the jvm, and even if you did have a native or web ecosystem the design choices they made seem to be, as far as I can tell, about the worst approach I’ve ever seen to cross platform interoperability. Ultimately the features they’ve added all follow this pattern of having pulled a good idea from elsewhere but having an implementation that seems to not fulfill the deeper reason for the feature. The only underlying principle seems to be “make java suck less”. That is, of course, a bar buried so low in the ground it’s in danger of being melted by the earths core, and I would say they did cross over that bar- kotlin does suck less than Java, but what’s astonishing to me is how for such a low bar they still seem to have managed to cross over it just barely. " [58]
- "...the parts about migrating gracefully to a new language reminded me a lot of my experience introducing Kotlin to an existing Java code base. Really good bidirectional interop with Java made it a total breeze to start small with an isolated section of the code we were comfortable throwing out and rewriting in Java if we decided Kotlin wasn’t for us. After we decided we liked it, it was painless to gradually convert existing code whenever we were making substantial changes. There never needed to be a “stop the world to convert to Kotlin and hope we got everything 100% correct” period on our roadmap; it just happened organically, bit by bit, as part of delivering features." [59]
- "Pretty much 95% of this list is why Kotlin is my primary programming language now. It's more productive because it accomplishes almost everything on this list out of the box on IntelliJ? IDEA. The only bits I generally need to add on are some Gradle plugins to handle linting (spotless or kolinter) no-friction Docker images (jib) and overtime amassing a list of very high quality libraries for specific tasks (Clikt for CLIs, Jackson for serialisation, etc). Couple all this together you get incredibly productive out of the box experience that is very easy to onboard new team-members onto. Pairing with this setup is also great, Code With Me is constantly getting better (pairing tool built into IDEA), being able to teach newbies keyboard shortcuts in IDEA to make them more productive etc. I think the latter stuff is probably more important to me now as I mostly take on lead roles, my own productivity has always been high but being able to make that more scalable has been immensely more valuable." [60]
- "Kotlin is kinda like Swift: great direction, but suffers from JVM platform and from comparability with Java." -- [61]
Comparisons:
- https://kotlinlang.org/docs/reference/comparison-to-java.html
- http://nilhcem.com/swift-is-like-kotlin/
- https://agilewombat.com/2016/02/01/scala-vs-kotlin/
- vs Rust: "Rust's typesystem really makes it a great fit for business applications. Totally agree. Kotlin comes close, though. Rust itself is production ready, but not the ecosystem." -- [62]
- vs Rust: "Error Handling. When it comes to null safety, Kotlin and Rust are mostly equivalent in practice. There are some finer distinctions here between union types vs sum types, but they are irrelevant in real code in my experience. Syntactically, Kotlin’s take on ? and ?: feels a little more convenient more often. However, when it comes to error handling (Result<T, E> rather than Option<T>), Rust wins hands down. Having ? annotating error paths on the call site is very valuable. Encoding errors in function’s return type, in a way which works with high-order functions, makes for robust code. I dread calling external processes in Kotlin and Python, because it is exactly the place where exceptions are common, and where I forget to handle at least one case every single time. " [63]
- vs Rust: " Basic Conveniences They way I typically code in Kotlin/Java is fairly data centric I say, Kotlin data classes (and coming soon Java records) make immutable data straightforward. Definitely miss traits here though, designing for extensibility upfront it more difficult and can lead to rearranging code or needing intermediate “adapter” classes. Extension methods help make this less painful though. Kotlin has sum types in the form of sealed classes (coming to java soon), so it’s possible that the plugin just doesn’t use them for some reason. Sealed classes aren’t as nice to match against since Kotlin doesn’t have real pattern matching (though Java will soonish!). It uses flow typing to tell the compiler “treat this var as type X” in the scope of the match. No disagreement with Results, I much prefer them to exceptions. Other Kotlin niceties I enjoy are default/named args for methods and constructors, the lambda syntax, extensions methods, shorthand functions/properties, and lambdas with receivers that enable building DSLs." -- [64]
- vs Rust: "Concurrency: Rust definitely wins on this front." -- [65]
- vs Java https://blog.frankel.ch/miss-in-java-kotlin-developer/
- vs Scala, Java: https://elizarov.medium.com/why-im-not-enthusiastic-about-java-10-b2d789b6d42a
Gotchas:
- "kotlin guarantees nullability behavior, but this can be broken at the interface with java in a couple of cases. If the java code lack @nonnull @nullable annotations, it is up to you to handle their nullability. Similarly, kotlin classes instantiated from java code can mess with nullability. If you data class contains a nonnull property and you instantiate this class with Moshi (a json parser), if the corresponding json field is missing you end up with a null field on a nonnull property." [66]
---
Crystal
"syntax inspired by the language Ruby...compiled language with static type-checking" [67]
Opinions:
- "looks almost like Ruby, but it is compiled and statically typed and fast. It supports OOP like Ruby does and has lots of nice features in it, like type inference, optional types, CSP for concurrency and compile-time macros, like Golang codegen, but inside the compiler..." [68]
- "Since the language is still young, it still has time until it will be production ready. I’d like Crystal concurrency to use all the cores available, like Go, instead of having to manually fork in order to do that. I would rather that methods that throw exceptions would return result type instead, so error handling would be explicit. I wish that Enums could have values in them, so we could use Enums just like Swift enums and OCaml variants. Better editor support could help too: autocompletion and type hints on hover have been an awesome addition. Moreover, in Scry, the language server’s autocompletion works on the standard library but not on user code. I also have a small fear that Crystal wouldn't make it to version 1.0." [69]
REBOL
http://www.rebol.com/rebolsteps.html http://www.rebol.com/tutorials.html http://www.rebol.com/tutorials.html http://www.rebol.com/nutshell.html http://www.rebol.com/r3/docs/index.html http://www.rebol.com/r3/docs/guide.html http://www.rebol.com/rebol-intro.html
I don't actually know REBOL well enough to know if it belongs in this chapter...
"I have been looking into quicker languages for scripting and scripting desktop applications. I found http://www.rebol.com/ which is fantastic and powerful without being overcomplicated." -- gscott
Wren
http://wren.io/ https://github.com/wren-lang/wren
I don't actually know Wren well enough to know if it belongs in this chapter...
Features
"All fields are private in Wren—an object’s fields can only be directly accessed from within methods defined on the object’s class....In short, if you want to make a property of an object visible, you need to define a getter to expose it...To allow outside code to modify the field, you need to provide setters to provide access...This might be different from what you’re used to, so here are two important facts: * You can’t access fields from a base class. * You can’t access fields on another instance of your own class." -- [70]
- "method lookups aren’t arbitrary lookups of a string into a method table, but rather slotted at compile time. It makes method lookup much faster at the expense of losing a bit of dynamism: in my opinion both of those are wins!" -- [71]
Opinions
Wren implementation and internals
- the Wren language source code looks like a good example implementation to read. It is a simple high-level language with a small implementation meant to be embedded. The docs claim that "The VM implementation is under 4,000 semicolons. You can skim the whole thing in an afternoon. It's small, but not dense. It is readable and lovingly-commented."
Squirrel
http://squirrel-lang.org/ https://en.wikipedia.org/wiki/Squirrel_(programming_language)
small, embeddable
Cito
compiles to C, C++, C#, Java, JavaScript?, Python, Swift and OpenCL?
https://github.com/pfusik/cito https://github.com/pfusik/cito/blob/master/ci.md
todo: i'm not really sure if everything in this file is actually imperative, memory-managed, and oop! check!