1. 8

I want to learn an “alien” language to expose myself to unfamiliar programming styles (I mostly work with Python on data science stuff). While I don’t have a rigorous definition for “alien” languages, they typically refer to stuff like Nim, Julia, Rust, Go, Zig, Elixir, Erlang, OCaml, Common Lisp, etc, which has gained quite some momentum but is yet to become a Big Language like C++, JavaScript, and Python. Note that I’m learning the alien language just for a fun adventure, and am not expecting the skill to find me a better-paid job.

What are the features of the alien language of your favorite, and what kind of fun will I have by learning it? I surely can go to the language’s homepage and read the “Features” section, but that would be inevitably biased. Additionally, I would appreciate comparisons between different languages to understand their focus better.

  1.  

  2. 9

    From the “non-marketing” features of Erlang/Elixir/BEAM as a whole (so excluding processes, OTP, supervision trees, etc. that you can read in almost any article about it) - binary pattern matching is awesome, and is a thing that made me love binary data formats. It is so simple to work with, that it is IMHO the most irritating thing when I need to work with binaries in any other platform.

    For example to encode integer in BARE you need to do (rough example):

    decode_int(<<1:1, N:7, Rest/binary>>) -> N + (decode_int(Rest) bsl 7);
    decode_int(<<0:1, N:7>>) -> N.
    

    And all bit twiddling magic is handled for you. It was pretty obvious decision to include such construction in Erlang, but it is a shame that not many languages provide something similar to this.

    1. 8

      The Elements of Programming Style:

      The book contains 33 different styles for writing the term frequency task. The styles are grouped into nine categories: historical, basic, function composition, objects and object interactions, reflection and metaprogramming, adversity, data-centric, concurrency, and interactivity.

      Seven Languages in Seven Weeks:

      In this book you’ll get a hands-on tour of Clojure, Haskell, Io, Prolog, Scala, Erlang, and Ruby.

      1. 7

        J really bent my head. The approach is so different it feels like learning to program again. Each line is it’s own fun little puzzle. There aren’t many “concepts” to wrestle with like in languages with unique type systems or logic languages. You just get a few different starting tools that are quick to grok, but then have to figure out how to actually use them to do anything real.

        As a data science person, you probably have some exposure to array programming ideas through stuff like numpy. But J and other APLs go 100% in that direction, and the world looks really different through that prism.

        I never really write serious J. But the REPL is my go-to calculator and I have a personal library of work and life related functions that I add to as needed. It’s crazy how good it is as a scratchpad, and how much the language conforms to how you think about a domain. Forth has a similar property to a greater degree, but feels like it gets “unruly” in a way that J doesn’t.

        Familiarity with Array Programming has also helped me come up with cleaner designs in other languages. It’s also due for a renaissance imo, as GPUs and SIMD become more relied upon and as the data people realize how wasteful we’ve been with our machines.

        1. 3

          a personal library of work and life related functions

          Would you mind sharing some examples? Not asking for source code, just curious as to the sort of tasks you use this for :)

          1. 2

            APL is def alien. It feels like an insanely powerful programmable calculator with the keys labeled with mysterious glyphs. The calculator’s data model is basically a Rubik’s cube filled with numbers, and to get good at APL you have to learn the macros / idioms that let you do a really powerful thing with a canned series of twists (I mean keystrokes).

          2. 6

            Prolog and forth will both feel unfamiliar. Rust will feel very different. Julia will give you the experience of numerical programming in something different.

            1. 1

              Prolog and forth will both feel unfamiliar.

              Thanks for mentioning them! I should note that I’m just looking for a different programming experience, and the language doesn’t have to be new.

            2. 5

              Haskell is interesting because it is one of the few examples of a pure function language. All data is represented by immutable values; all functions are pure (no side effects); all variables are immutable (no assignment statement). Coming from a background of object-oriented programming, it wasn’t obvious to me that you could do general purpose programming without mutable objects or mutable state, and once I clued in, it really changed the way I think about programming. Plus, Haskell has a very powerful type system. Learning the idioms of type-directed programming also changes the way you think about programming.

              Somebody suggested J, but I will suggest the K programming language instead. K is much simpler. The entire language cheat sheet fits on one page. K is rigorously simple, comprised of a small number of orthogonal types and operators that are highly composable. Most languages are an agglomeration of features, which are DSLs for different domains of programming. Like, there is a module feature, which has hierarchical module names, an ‘import’ statement which is its own mini-language, etc. In an OOP language there is a class feature, and a fairly complex DSL for defining classes, inheritance, etc. K doesn’t have features, it has idioms. You do everything by composing this small set of orthogonal operators. The operators are for the most part single ASCII characters. Each ASCII punctuation character has its own special meaning. K is extremely terse. Once you learn the idioms, K programs can be 100x shorter than programs in conventional languages. K programmers rely a lot less on libraries than in Python. The K idiom for some simple Python library function (which could be a composition of 3-5 K operators) is often fewer characters than the name of the Python library function, so why use a library if it’s more typing than using the idiom.

              1. 5

                Languages that blew my mind where: Lisp, Prolog, APL, FP, Forth, Strand, Verilog, in roughly that order. Note that it is not sufficient to just dabble with a language to get the real “feel” for its peculiarities. Ideally, one should try to implement a language to truly attempt to understand it.

                1. 4
                  • Erlang: Message-passing everywhere, thanks to the actor model. Feels like creating new biological systems, not just programming. In a good way.

                  • Prolog: Encode rules. Encode a metainterpreter to redefine search. Suddenly, you have a very flexible system. Not just the cliche about Prolog. The first Erlang implementations were built this way.

                  • Haskell: Laziness and point free style enable extreme composition, and facilitate calculating programs. Read about Squiggol to understand the deep implications this may have. The Joy language is also worth mentioning here.

                  • Idris: Dependent types let you encode rich constraints that can be enforced at compile time. Liquid Haskell uses refinement types, which are a less expressive but more tractable alternative. And you still have the whole Haskell ecosystem at your disposal.

                  • Mozart/Oz: Many paradigms in the same language. Look up CTM, a great sequel to SICP.

                  • Julia: AOT compilation of specialized functions can lead to wicked speedups. Multiple dispatch plus a clever dynamic type system may be all you need for number crunching.

                  • Rust: Nice type systems are also good for non-GC languages, and can enforce very practical guarantees (memory safety) for systems programming.

                  1. 3

                    If you’ve never written a Lisp before, I can recommend Janet as a nice introduction to that world.

                    1. 1

                      May I ask why do you like it, and how it compares to more traditional choices like Scheme and Common Lisp?

                      1. 2

                        Regarding the second point, they’re similar. The syntax is the same, and you have “similar enough” primitives for working with sequences. There are a few “big” differences, like most sequential data structures not being linked lists, but it still feels lisp-y to me.

                        Racket is another beginner-friendly Lisp if you’re looking for something resembling Scheme. It has a nicely-written guide. The Janet documentation might be a bit confusing if you don’t have prior experience with lisp.

                        1. 2

                          I have a few reasons that I like it.

                          I tried it on a whim for Advent of Code 2020, and ended up liking the PEGs quite a lot.

                          Then, as I’ve used it more and more, I’ve grown to like it for it’s macros, and for the rather practical sensibilities it has around it’s data structures. It is still very young in an ecosystem sense, so it’s a great chance to learn how to build things for a small ecosystem, and/or to practice hacking on C extensions, or writing things in Zig (there are some people working with zig with it).

                          I don’t have deep experience with Scheme and Common Lisp.

                      2. 3

                        I recommend this 3-part course on programming languages. It uses SML. It’s a fine language but I see that as the ‘price of entry’ to learn from Dan Grossman who is a fantastic teacher. It will give you the tools to make sense of all the languages you mention. If I recall correctly, in an early lecture Dan calls this course his ‘magnum opus’ and it shows.

                        1. 3

                          After writing in C for the past year, I find Scheme to be a breath of fresh air. It has got all the advantages of being a Lisp (powerful macros, basically no syntax) but is also simpler in regards to Common Lisp. I think that is why I prefer it. Instead of having a tool for every problem, you have a couple tools you use to create your own solutions. Additionally, implementations like Chicken Scheme allows compilation to a binary, which is quite handy and something Common Lisp sorely lacks (no, I do not count sb-ext:save-lisp-and-die).

                          1. 3

                            Icon is a general-purpose programming language from the late 70s that has a kind of backtracking built into its evaluation.

                            Instead of boolean values, every expression can either “fail” or “succeed,” optionally with a value. There are various language constructs that “retry” in the case of failure. You can write an expression like this:

                            (a | b) < 10
                            

                            And it “basically” means a < 10 || b < 10. | creates an ad-hoc “generator” of values, and if an expression fails with one value then the evaluation, like, backtracks to the nearest generator and tries the next value (if it can). It’s been a long time since I read about it; I might be getting this very wrong. But I recall you can write weird things that look like simple statements but are actually loops because of this ability to “project” generators through expressions. So you can write:

                            every print(!lines)
                            

                            Instead of the typical (pseudocode):

                            for line in lines:
                              print(line)
                            

                            Wikipedia gives a pretty good overview of this:

                            https://en.wikipedia.org/wiki/Icon_(programming_language)#Goal-directed_execution

                            It feels very alien to me. Apparently it copped this from SNOBOL, which I know absolutely nothing about.

                            I have never actually written Icon, but I read a book about it because I thought it would be interesting and mind-altering. It’s freely available online as a PDF: https://www2.cs.arizona.edu/icon/lb3.htm

                            Obviously this isn’t… a language you should learn. But it’s an interesting weird unfamiliar feature. I’ve sometimes thought about writing an awk alternative based around parser combinators that uses this evaluation model, as it’s nice and concise but seems unsuitable for a general purpose language.

                            I have a lot of experience with OCaml and would say that it’s not as alien as you might expect. Module functors are much easier to wrap your head around than (e.g.) typeclasses, I think. It would be a very gentle introduction to some interesting concepts though, if you’re curious about it.

                            Haskell is far more mind-expanding, and was the “alien language” I decided to pick up seven years ago. It has been the most rewarding (intellectually/financially) thing that I have ever studied. I have never been paid to write Haskell, but it changed the way that I think about programming in every other language and deepened my understanding of… everything. Sounds cultish. Can’t deny that. But it completely changed the way I thought about using types, allowed me to recognize patterns that I never noticed before… there aren’t really any features that I can point to in the language; it’s just the mental shift of thinking about typed data transformations instead of thinking about moving the instruction pointer around.

                            I would recommend against reading Learn You A Haskell except as a gentle introduction to the syntax. It is for some reason the default starting point, but it does nothing to show you how to “think” in Haskell or how to actually write programs in Haskell. For example that book never mentions cabal – Haskell’s cargo or npm or what have you – and because Haskell is the opposite of batteries included, there isn’t a whole lot you can do without cabal. (Whereas most languages have, you know, strings and stuff built in to the standard library, almost everything in Haskell is defined in an external package, for better or worse.)

                            1. 2

                              Seconding what you said about Learn You A Haskell. While it works nicely as a “whirlwind tour” of what Haskell can do, once you’re done with it you’d have a very hard time writing even a simple program because it doesn’t do much actual teaching. My personal favorite beginner Haskell book is Haskell Programming from First Principles, but unfortunately it’s not free like LYAH is. I think it’s worth it if you want to come out the other side actually knowing how to read and write Haskell, though.

                            2. 2

                              Personally I got the most out of Erlang (in terms of mind expansion a la Sapir-Whorf and also in terms of usefulness as a tool for building systems), and I learned about it via the Seven Languages in Seven Weeks book mentioned by another commenter. There’s a sequel to that one out by now I believe.

                              1. 2

                                What I think are the most unique aspects of some languages you listed:

                                • Julia: the way it’s dynamically typed but also uses types to generate fast code. This is totally unique to Julia as far as I can tell.
                                • Rust: borrow checker, lack of mutable aliasing, fearless concurrency, etc. Also appears to be unique.
                                • Go: the style of concurrent/parallel programming using goroutines and channels, although I will note it’s logically “threads and channels”. (Also I’ve heard that there are lots of big Go programs that don’t use channels at all, which might surprise the designers of Go.)
                                • Zig: compile time metaprogramming and how it subsumes other language features.
                                • OCaml: like Standard ML, I would say it’s worth it just to program with algebraic data types. You can sort of fake this in TypeScript and other languages but it’s worthwhile to use the “original”.

                                I also recommend learning shell :-) It will expand your thinking:

                                https://www.oilshell.org/blog/tags.html?tag=shell-the-good-parts#shell-the-good-parts

                                Particularly around polyglot programming, i.e. factoring systems into processes written in different languages. And maintaining/operating/administering those systems, not just writing them.

                                You get a different view on software once you have to admin your own code :) The operator’s view is inherently dynamic, not static.

                                1. 1

                                  One of the most alien languages I’ve come across (and hasn’t been mentioned yet) is INRAC. It was commercially available, and there were commercial products available written in it, but there’s not much on the Internet about it. The alien thing about INRAC is the flow control, which is not so much “controlled” as it is “somewhat loosely guided” (read: non-deterministic).

                                  Each line of code is a subroutine, except if it’s followed by an explicit “goto next line”. Each line also contains a label, which doesn’t have to be unique. Lines (or subroutines) with the same name don’t even have to be sequentially listed in the source. Calling subroutine “foo” will pick one subroutine named “foo” at random and execute it. You can also specify a pattern, so you can call a subroutine “f*o” that will pick one subroutine whose name matches and execute it.

                                  1. 1

                                    To me, pure-functional languages have felt the most alien, to the extent that I have never gotten comfortable with them. I’d recommend trying Haskell as it has a good gentle intro in the form of Learn You A Haskell. Scala is another option; it has “training wheels” in that it lets you mutate state if you really want to. I couldn’t stand Erlang’s syntax, but that’s just me.

                                    FORTH and LISP are fascinating from an implementation POV; they’re both very minimal, implemented mostly in themselves, and I’ve enjoyed reading through simple interpreters, like the very literate jonesforth.S. I don’t find them much fun to do Real Work in, though, because of that minimal syntax (reverse-Polish and forwards-Polish, respectively.)

                                    Since you mentioned Nim: I love the language, but I don’t think it’ll feel alien to you at all. It feels very Pythonic despite all the actual differences, and you can go a long time without remembering that you’re actually compiling to native code. (Actually Nim’s macros are really interesting — Rust has those too, and they both derive from the macros that most LISPs have had since forever.)

                                    Zig is interesting in the way it mixes compile-time (comptime) execution into code. A lot of languages have compile-time stuff (I think D was first, and C++ has an increasing amount) but Zig feels unique in the way you can blend comptime and runtime in the same function, and in the elegant way it uses comptime to implement generics.

                                    Rust is a good language with interesting novel concepts like the borrow checker, and very au courant of course, but the borrow checker makes it kind of a pain to learn. The compiler will feel like a very helpful but very strict professor standing behind you with its ruler raised, ready to whack your knuckles the moment you stray, then explain in detail how you broke the rules.

                                    1. 2

                                      forwards-Polish

                                      Isn’t it just “Polish notation”, if it’s not RPN?