5 Programming Languages You Should Really Try

For some strange reason, the vast majority of my blog readers are Python Developers. I wrote two articles on Python a long time ago and honestly try to avoid python when I can. So here's an article for you purveyors of Python -- you sultans of snakes.

Note: This article is still likely relevant even if you're not a Pythonista.

For those who aren't aware, Linguistics and Grammars are particularly interesting to me. I really, really enjoy looking into new languages and comparing them to what I already know. Originally, this started as a purely syntactic thing, but as I learned more about compilers, virtual machines, and performance I started to compare those as well. We'll cover a little bit of everything in this post as I suggest a few great languages that you've probably not tried yet. I'll count down in terms of favorites:

5. Nim

Efficient and expressive programming. Nim is a systems and applications programming language. Statically typed and compiled, it provides unparalleled performance in an elegant package.

Nim is a language near and dear to my heart, although I'll be honest and admit that I haven't had as much time with it as I wish. The little I have toyed with the language was a delightful experience. Nim is interesting as it compiles down to C, C++, or JavaScript. This allows you to tackle systems programming in Nim with (almost) the gusto that you'd expect in C or C++. Nim also takes a page from Clojure's book in that it allows you to compile to JavaScript. The build process for Nim is what any systems developer would expect. It's compiled, so you produce a nice portable (dependency-free) binary. Just target your build and run!

Nim is also high extensible via templates and macros. These are processed as compiler time transformations. That's pretty cool, but what if I told you the compiler was extensible too? Well great news, in nim, it is!

Python Developers: Nim takes a ton of concepts from Python's book. Specifically several of the constructs in Nim's standard library are pretty Pythonic.

C, C++, Java Developers: Nim should syntactically look comfortable, but one interesting benefit you'll get with Nim is a configurable garbage collector. You can choose to use a deferring garbage collector something real-time and deterministic. Pretty neat!

To give you some syntax to compare, here's quicksort in Nim, courtesy of Rosetta Code:

proc quickSort[T](a: var openarray[T], inl = 0, inr = -1) =  
  var r = if inr >= 0: inr else: a.high
  var l = inl
  let n = r - l + 1
  if n < 2: return
  let p = a[l + 3 * n div 4]
  while l <= r:
    if a[l] < p:
      inc l
      continue
    if a[r] > p:
      dec r
      continue
    if l <= r:
      swap a[l], a[r]
      inc l
      dec r
  quickSort(a, inl, r)
  quickSort(a, l, inr)

var a = @[4, 65, 2, -31, 0, 99, 2, 83, 782]  
quickSort a  
echo a  

4. Go

Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.

Google's Go is an interesting language. In fact, Python used to be what I would recommend to people getting into development, but I think I'm at the point that I would recommend go instead now. For those unaware, Go has been around since 2007 although it has only recently caught fire with it's popularity and wasn't announce by Google until 2009. I really like how simple and straightforward Go is. It's easy to accomplish a lot in a relatively small amount of time -- one of my initial selling points on Python many years ago. The build process for Go is similar to Nim's. You get a nice portable binary and can run with that!

Async in go is simplified into the concept of channels which are a breeze to work with. You'll see these in async code alongside of goroutines which simplify the concept of multithreading.

Python Developers: Go clearly emanates from C, but with an interesting twist focused on brevity, simplicity and safety. Similarly to Python's "Batteries Included" go ships with a really great package manager to help you get started as quickly as possible.

C, C++, Java Developers: Syntactically, Go is really similar to this suite of languages. Go is (almost certainly) going to be slightly less performant than C, but still very fast. Another great selling point for Go is it's focus on types and interfaces (if you're not using interfaces you really should be).

To give you some syntax to compare, here's quicksort in Go, courtesy of Rosetta Code:

package main

import "fmt"

func main() {  
    list := []int{31, 41, 59, 26, 53, 58, 97, 93, 23, 84}
    fmt.Println("unsorted:", list)

    quicksort(list)
    fmt.Println("sorted!  ", list)
}

func quicksort(a []int) {  
    var pex func(int, int)
    pex = func(lower, upper int) {
        for {
            switch upper - lower {
            case -1, 0: // 0 or 1 item in segment.  nothing to do here!
                return
            case 1: // 2 items in segment
                // < operator respects strict weak order
                if a[upper] < a[lower] {
                    // a quick exchange and we're done.
                    a[upper], a[lower] = a[lower], a[upper]
                }
                return
            // Hoare suggests optimized sort-3 or sort-4 algorithms here,
            // but does not provide an algorithm.
            }

            // Hoare stresses picking a bound in a way to avoid worst case
            // behavior, but offers no suggestions other than picking a
            // random element.  A function call to get a random number is
            // relatively expensive, so the method used here is to simply
            // choose the middle element.  This at least avoids worst case
            // behavior for the obvious common case of an already sorted list.
            bx := (upper + lower) / 2
            b := a[bx]  // b = Hoare's "bound" (aka "pivot")
            lp := lower // lp = Hoare's "lower pointer"
            up := upper // up = Hoare's "upper pointer"
        outer:
            for {
                // use < operator to respect strict weak order
                for lp < upper && !(b < a[lp]) {
                    lp++
                }
                for {
                    if lp > up {
                        // "pointers crossed!"
                        break outer
                    }
                    // < operator for strict weak order
                    if a[up] < b {
                        break // inner
                    }
                    up--
                }
                // exchange
                a[lp], a[up] = a[up], a[lp]
                lp++
                up--
            }
            // segment boundary is between up and lp, but lp-up might be
            // 1 or 2, so just call segment boundary between lp-1 and lp.
            if bx < lp {
                // bound was in lower segment
                if bx < lp-1 {
                    // exchange bx with lp-1
                    a[bx], a[lp-1] = a[lp-1], b
                }
                up = lp - 2
            } else {
                // bound was in upper segment
                if bx > lp {
                    // exchange
                    a[bx], a[lp] = a[lp], b
                }
                up = lp - 1
                lp++
            }
            // "postpone the larger of the two segments" = recurse on
            // the smaller segment, then iterate on the remaining one.
            if up-lower < upper-lp {
                pex(lower, up)
                lower = lp
            } else {
                pex(lp, upper)
                upper = up
            }
        }
    }
    pex(0, len(a)-1)
}

3. F#

F# is a mature, open source, cross-platform, functional-first programming language. It empowers users and organizations to tackle complex computing problems with simple, maintainable and robust code.

Let's get into my favorite territory - functional programming languages. Have you had the chance to check out F# yet? No? Well you're missing out on a lot. Let's clear the air about the negatives - It was created as a Microsoft language. You're going to get the most from the language if you can leverage the .NET framework. You don't HAVE to do this, however, and can build F# against Mono, too.

I was first exposed to Metalanguages in college and they blew my mind really frustrated me. During the final weeks of my course on Functional Programming (with PolyML), it all kind of clicked and I really started to dig the language family. That being said, after doing a little bit of research, I felt that Metalanguage's like PolyML and F# (wasn't aware of F# at the time) just weren't practical. Later in my life I found F# and fell in love. If I ever end up working in a .NET shop, you can bet your ass I'm working with F#.

The language is syntactically extremely different from everything you've seen above. Functional languages often take a very declarative approach on problem solving and leverage recursion and pattern matching to make the most of their toolkit. F# is no exception to this paradigm.

.NET Developers: A functional approach on your standard toolkit. If you want to try F# and need help introducing it to your team consider building a CLI with the language. It's an excellent tool for this and really showcases its strengths.

Python Developers: Python is an outstanding tool for writing CLIs. F#, too, is an outstanding tool for writing CLIs. The language feels like a strong scripting language but provides so much more. In fact, tools like Pattern Matching make writing a CLI tool such an ease!

C, C++, Java Developers: Take a walk on the wild side. In my opinion, the biggest growth moment in my career as an engineer was the day I committed to learning functional programming. I still write Java a lot but you can see functional influence in a lot of ways. F# provides a great opportunity to help teach you these functional programming skills that can be applied in any language. It will also make you want to file an RFC for pattern matching in Java.

To give you some syntax to compare, here's quicksort in F#, courtesy of Rosetta Code:

Some things to keep in mind - rec defines a function as recursive so that the function has access to a binding of itself. The line under the function definition is a base-case pattern matcher against an empty list. The one below that matches on a list with a head element and a tail.

let rec qsort = function  
    [] -> []
    | hd :: tl ->
        let less, greater = List.partition ((>=) hd) tl
        List.concat [qsort less; [hd]; qsort greater]

2. Rust

Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety.

Above is a quote from the Rust website. I couldn't give a better quick summary of this language if I tried. Rust is fantastic. I first got into Rust with hardware hacking on the Arduino and just fell in love with the language. Rust focuses on the things that I love about Clojure but provides them in a systems language. The language itself focuses on immutability and thread-safety. The community is wonderful, supportive, and very responsive and open to feedback.

The difficult and sometimes discouraging part of writing Rust is "fighting" the compiler. The reason that the compiler seems so aggressive is because it's helping you prevent issues and write safe code. Mainly, new Rustaceans fight the borrow checker as the idea of borrowing is usually a very new concept. For those who are unaware, the way Rust maintains its ability to stay threadsafe is by "borrowing" references from one scope into another. This can be really difficult at first but once you learn how borrowing works (as well as the object lifecycle) Rust becomes a delightful experience. Plus, it runs blazingly fast!

Python Developers: If you want a new experience that will focus on teaching you the values of immutability and the merits of a compiler (you may already know these things), look no further. The community is one of the few communities that I feel is better (that's right, better) than the Python community. If you've ever wanted to get into systems programming but have had fear of SegFaults or memory management, try Rust.

C, C++, Java Developers: Another language in a style that should be syntactically familiar to you, but Rust is a completely different paradigm on memory management. The Lifecycles cause heap values to drop once they leave scope which helps maintain a manageable set of memory addresses. Rust also supports the unsafe keyword, should you feel the need to get down and dirty with C like code, however writing unsafe always makes me feel guilty and usually leads to refactoring.

To give you some syntax to compare, here's quicksort in Rust, courtesy of Rosetta Code:

fn main() {  
    println!("Sort numbers in descending order");
    let mut numbers = [4, 65, 2, -31, 0, 99, 2, 83, 782, 1];
    println!("Before: {:?}", numbers);

    quick_sort(&mut numbers, &|x,y| x > y);
    println!("After:  {:?}\n", numbers);

    println!("Sort strings alphabetically");
    let mut strings = ["beach", "hotel", "airplane", "car", "house", "art"];
    println!("Before: {:?}", strings);

    quick_sort(&mut strings, &|x,y| x < y);
    println!("After:  {:?}\n", strings);

    println!("Sort strings by length");
    println!("Before: {:?}", strings);

    quick_sort(&mut strings, &|x,y| x.len() < y.len());
    println!("After:  {:?}", strings);    
}

fn quick_sort<T,F>(v: &mut [T], f: &F)  
    where F: Fn(&T,&T) -> bool
{
    let len = v.len();
    if len >= 2 {
        let pivot_index = partition(v, f);
        quick_sort(&mut v[0..pivot_index], f);
        quick_sort(&mut v[pivot_index + 1..len], f);
    }
}

fn partition<T,F>(v: &mut [T], f: &F) -> usize  
    where F: Fn(&T,&T) -> bool
{
    let len = v.len();
    let pivot_index = len / 2;

    v.swap(pivot_index, len - 1);

    let mut store_index = 0;
    for i in 0..len - 1 {
        if f(&v[i], &v[len - 1]) {
            v.swap(i, store_index);
            store_index += 1;
        }
    }

    v.swap(store_index, len - 1);
    store_index
}

1. Clojure

Clojure is a robust, practical, and fast programming language with a set of useful features that together form a simple, coherent, and powerful tool.

If you didn't see this coming, then thanks for checking out my blog for the first time! Clojure is a Lisp that (often) runs on the JVM. It's a symbiotic language which means that I can be ran anywhere that it has a host for. In fact, another common use-case for Clojure is compiliation down to JavaScript, called ClojureScript. If you're in the web development community, you've probably heard of ClojureScript as it's really caught on in regards to it's popularity lately thanks to Om and Om Next.

Clojure is the brainchild of the wizard known as Rich Hickey. The community as a whole provides a refreshing perspective on software development and having Rich at the helm is nothing to discount. There's a database written with Clojure in mind (Datomic) and the tooling for the language is fantastic.

The structure of lisp and the paradigms behind it are nothing short of liberating. When functions dictate your code everything becomes easier to reason with. In fact, it allows you to easily write and reason about macros and I've struggled with these concepts historically in other languages that support them.

Speaking of tools, on the JVM, you can leverage any and all Java libraries in your Clojure code. This interoperability gives Clojure a massive collection of libraries despite the community being smaller than the Java community. A downside of Clojure is that it's limitation is often the same that confines the JVM (no tail call recursion), but Clojure makes a strong effort to abstract these concerns or provide alternatives.

In my opinion, Clojure is a tool that can be used for almost any job and I love the idea of that. There's even a library for writing Android applications in Clojure (and a pretty notable app called Swiftkey written in Clojure) and a ton of libraries for graphics processing.

I'll try to avoid ranting for hours about clojure, but if you're interested in learning more about it, you can find my articles on the language here.

Python Developers: If you're one of the python developers that keep coming back to my blog for some reason, you'll see most of my new articles are in Clojure. I am so very happy to teach you or work with you to help you learn about this language. As for everyone else, Clojure gives you an exciting approach on new paradigms in programming that you won't ever find in Python.

C, C++ Developers: Clojure probably won't be much of a help if you're looking for systems development, however, if you've never touched Lisp you can learn a ton from writing the language. And if you've never written Lisp, I can't recommend a better Lisp than Clojure. C and C++ developers will likely love the power behind Macros so be sure to give that a shot!

Java Developers: You can try Clojure without ever leaving your JVM. Clojure is catching on quickly in the financial tech industry and makes for excellent DSLs that interop with Java in an immaculate fashion.

To give you some syntax to compare, here's quicksort in Clojure, courtesy of Rosetta Code:

(defn qsort [[pivot :as coll]]
  (when pivot
    (lazy-cat (qsort (filter #(< % pivot) coll))
              (filter #{pivot} coll)
              (qsort (filter #(> % pivot) coll)))))

Permalink

Clojure + Kibit & Eastwood

I've been writing Clojure for a while now, but my day job is still predominantly JavaScript and Java. There are two tools that I use every single time I write JavaScript and Java code. Respectively, a linter and a static code analyzer. Recently, I set out to search for similar tools in the Clojure domain.

Enter Eastwood

Named after a fantastic actor, Eastwood is a linter for Clojure code. Also like the many roles the actor plays, Eastwood is pretty aggressive in the checks that it runs against your code. However, like Clint Eastwood in The Bridges of Madison County, Eastwood can also be understanding. You can configure Eastwood to meet the demands of your project, but it ships with a great default configuration too!

Implementing Eastwood is extremely simple. You can add the Eastwood plugin to your project if you're using leinengen or incorporate the library into your build pipeline if you're using boot. I've still yet to be sold on boot (and this post is a bit pressed for time), so I'll only be showing you how to incorporate the plugins into leinengen. Modify your project.clj to include the Eastwood plugin:

(defproject myproject "0.0.1"
  :description "Eastwood Sample Project"
  :license "Eclipse Public License 1.0"
  :url "http://www.bradcypert.com"
  :dependencies [[org.clojure/clojure "1.8.0"]]
  :plugins [[lein-tar "3.2.0"]
            [jonase/eastwood "0.2.4"]])

Once you've done this step, you can simply run lein eastwood from the terminal to lint your clojure application! An example output from one of my application is as follows:

== Eastwood 0.2.4 Clojure 1.9.0-alpha16 JVM 1.8.0_31
Directories scanned for source files:  
  src test
== Linting app.routes.users ==
src/app/routes/users.clj:133:43: suspicious-expression: -> called with 1 args.  (-> x) always returns x.  Perhaps there are misplaced parentheses?  
src/app/routes/users.clj:115:3: constant-test: Test expression is always logical true or always logical false: true in form (if true (do (users/update-user-password {:hash (:id params), :pass (:pass params)}) (ok)) (bad-request))  
== Linting app.routes.login ==
== Linting app.helpers.helpers ==
== Linting app.routes.inbox ==
== Linting app.middleware ==

You can see from the example output that Eastwood found an issue with users.clj line 133. The issue is that there's a suspicious expression: specifically, we're threading x into nothing. Seems like a good thing for us to clean up! Below that, you'll see that our if expression is always checking against true. Specifically, because our code is (if true ... ...). It looks like this was probably added as a quick solution, and I wouldn't be surprised to find a TODO above that expression. Regardless, that's an example of how to use Eastwood to help lint your Clojure code.

Kibit

Kibit is another tool, specifically for static analysis of your codebase. Kibit is literally one of my favorite tools in the clojure ecosystem and I can't recommend this enough to newcomers to Clojure. Kibit provides a great opportunity to write code and learn a more idiomatic way to solve the same problem. It also introduces you to some of the "combination" expressions like if-let. Kibit can be incorporated similarly to Eastwood, but serves a different purpose. Let's go ahead and add kibit to the above project definition as well. Note: You don't need Eastwood for Kibit or vice-versa.

(defproject myproject "0.0.1"
  :description "Eastwood Sample Project"
  :license "Eclipse Public License 1.0"
  :url "http://www.bradcypert.com"
  :dependencies [[org.clojure/clojure "1.8.0"]]
  :plugins [[lein-tar "3.2.0"]
            [jonase/eastwood "0.2.4"]
            [lein-kibit "0.1.5"]])

Let's run lein kibit, you'll see output like this:

At /Users/brad/Projects/podcasts/app/src/app/db/processors.clj:14:  
Consider using:  
  (update-in podcast [:feed] podcast-service/parse-feed)
instead of:  
  (assoc podcast :feed (podcast-service/parse-feed (:feed podcast)))

At /Users/brad/Projects/podcasts/app/src/app/db/processors.clj:30:  
Consider using:  
  (when (not exists?)
    (doall
      (map
        (partial notifications/new-episode podcast episode)
        subscribed-users)))
instead of:  
  (if (not exists?)
    (doall
      (map
        (partial notifications/new-episode podcast episode)
        subscribed-users))
    nil)

At /Users/brad/Projects/podcasts/app/src/app/modules/auth.clj:17:  
Consider using:  
  (if-not (some nil? [item source]) (hashers/check item source) false)
instead of:  
  (if (not (some nil? [item source])) (hashers/check item source) false)

Kibit will actually scan your code and check it against patterns with core.logic to help determine how to simplify and reduce your code complexity. There output excerpt here shows two different suggestions: Simplifying an if to a when and condensing an if and not to an if-not. You can actually run lein kibit --replace and it will fix these issues for you. If you're afraid of letting it automatically replace everything, you can even choose to run Kibit in interactive mode via lein kibit --replace --interactive. This will walk you through each occurrence and ask if you'd like to replace it with the suggestion provided.

We've recently added Kibit and Eastwood into our codebase for Porios and hope to see cleaner, more consistent code in the future. Have you had experience with Linters or Analyzers in Clojure? Let me know below!

Permalink

True. Designing a language entails making tradeoffs.

True. Designing a language entails making tradeoffs. I’m not sure why the decision was made for Clojure to behave this way, but I’m confident it was considered.

Choosing a language entails tradeoffs, too. Languages like Haskell behave in ways Clojure doesn’t, and maybe some of those ways are better. But in aggregate, there’s a lot of big things Clojure does that other languages don’t. It may not be perfect, but I try not to let perfect be the enemy of the good.

Permalink

The Missing Guide to Elixir

When it comes to choosing passion projects and side studies, CircleCI engineers have considerable freedom. One of our support engineers, Zachary Scott, has been spending some of his free time tinkering with Elixir, a dynamic, functional language. It has enough in common with Clojure — our language of choice here at CircleCI — that we thought folks would enjoy a deep dive into this (relatively) new language. Enjoy!

It’s probably no surprise that we’re excited about Elixir, a functional language built on Erlang VM that shares many of Clojure’s philosophies. Before I talk about Elixir’s design and why it’s so amazing, I’d like to share how I stumbled on this beautiful language.

Permalink

Documenting your architecture: Wireshark, PlantUML and a REPL to glue them all.

This article originally appeared on my blog

I recently had to document the results of the evaluation of a new system.

The proof of concept for the system included six possible configurations, each option having a significant architectural impact on the system.

To understand all six, I have been squinting at the logs from the servers plus the Chrome DevTools network panel, trying to correlate the requests with the responses and the traffic between the servers.

As part of the documentation I thought it would be important to have some sequence diagrams to explain the protocol between the different parts of the system.

But when trying to draw the sequence diagrams, I realized that all that squinting had just allowed me to grasp the general feeling of the difference between the options, but not enough to write down a proper and accurate description of each one.

Also, the prospective boredom of opening my least hated UML tool and spending some hours dragging and dropping boxes and fiddling around with lines, didn't fill me with joy.

Given that I already had the six combinations running for the proof of concept, couldn't I leverage on that?

The tools

First, we need to find out all the traffic between the components of the system.
For this we will use the venerable Wireshark.

Wireshark will allow us to capture any network traffic, filtering out anything unnecessary, plus it comes with a handy export to json feature to simplify the parsing of the output.

A snippet of what a HTTP request looks like:

wireshark-json-sample

Second, we will need to generate the UML diagrams. For this we will use PlantUML, which is a text based UML DSL with the accompanying libraries to generate images. Being text based, our problem of generating UML diagrams becomes one of string concatenation.

Lastly, we need some glue to transform the Wireshark JSON files to PlantUML text files. We will use Clojure but any Turing complete language would do. Of course, a Clojure REPL makes the task more pleasant.

The result

First, to show off, lets look at how one of the diagrams looks like:

keycloak-uma

This diagram requires 40 lines of PlantUML that look like:

browser -> backend: /api/datasets/ds-1 (536.0B)
browser <-- backend: 200 json (0.7KB)
browser -> backend: /api/library (525.0B)
browser <-- backend: 200 json (1.0KB)
note over browser, nginx: ->1.2KB/<-532.0B
note over browser, backend: ->4.4KB/<-5.3KB

The whole PlantUML code is here and the code can be found here.

If you are curious, the diagram corresponds to loading a Single-page application, doing authentication with OpenID Connect and authorizing an API endpoint with User-Managed Access.

Benefits

The benefits of using these three tools are:

  1. We are able to generate a set of diagrams that are accurate, giving you the confidence that you are not missing anything. Assuming no bugs in the parsing code.
  2. As the set of diagrams are generated using the same code, they all look consistent, both in the data that they contain and in their look and feel.
  3. The data, the diagrams and the code to generate them are all text, which means that can be version control and manually inspected or tweaked if required.
  4. If we decide to change any details about the diagrams, it will take no time to update all diagrams.
  5. Maybe the code to generate the diagrams can be used in other projects.
  6. The diagrams have the desired level of detail. For example, in the diagrams we have removed the loading of images, css and javascript files.
  7. You can add a great deal of detail to the diagrams, as the data capture has even the request/response, so you could parse them and extract the information that was relevant to your system.
  8. You can do all from your favourite IDE in an interactive fashion:

Drawbacks

Of course there are some drawbacks:

  1. We have to have the system working and we have to be able to sniff the traffic.
  2. The data capture can be huge, so some pre-filtering during the capture phase maybe necessary.
  3. There can be sensitive data in the capture. Be careful with the security!

More benefits!

Last, but probably the most important benefit, is that we have converted a tedious task into an enjoyable one.

I never thought I would say this but ... Happy documenting!

Permalink

ClojureScript method head recur in defrecord

An update in the ClojureScript 1.9.655 compiler release eliminates a difference with respect to Clojure for code making a recur to a defrecord method head. Hopefully this post is useful in the event that you encounter this situation!




Let's look at some example code to make things concrete.

Let's say you have a protocol:

(defprotocol ISearch
  (search [this coll]))

And, let's say you are making an instance using defrecord. Notice that the recur is to the search method head (and not a loop target):

(defrecord Search [item]
  ISearch
  (search [this coll]
   (when (seq coll)
    (if (= item (first coll))
     item
     (recur (rest coll))))))

The above is a contrived example. It will scan for and return an item if it is found in a collection. For example, this

(-> (->Search 1)
  (search [:a 1 "b"]))

yields 1, while

(-> (->Search :z) 
  (search [:a 1 "b"]))

yields nil.

The code above works fine in Clojure, but if you try it in ClojureScript 1.9.562 or earlier, you will get the following when attempting to evaluate the defrecord form:

recur argument count mismatch at line 7
…

“Ahh, of course,” I'm thinking, “I need to add this to the recur call.” And I revise it so that part looks like:

     (recur this (rest coll))

Things are working now. ¯\_(ツ)_/¯

But, this is actually not the right thing to do—the docstring for defrecord has this to say:

… Note also that recur calls to the method
head should *not* pass the target object,
it will be supplied automatically and can 
not be substituted.

If you are trying to write portable code (say, using .cljc), then you'd need to deal with this discrepancy.

This has been fixed with CLJS-2085, making it so that you can now compile the code as initially written above. Note that this applies to defrecord, deftype, and reify.

In order to not break existing ClojureScript code that is passing this (or some other value) as the first argument to recur, the compiler will continue to accept the code, but it will emit a diagnostic like this:

WARNING: Ignoring target object "this" passed in recur to protocol method head at line 7

So, if you happen to see this warning, and you know your code will only be used in ClojureScript 1.9.655 or later, you can safely remove the first argument to recur.

If you are seeing this warning being emitted for library code that cannot be updated, you can suppress :protocol-impl-recur-with-target. See Compiler Warnings.

If you are a library maintainer and wish to continue supporting ClojureScript 1.9.562 and earlier, prior code will continue to work, albeit while emitting a warning. If you'd like to avoid this warning, one optional workaround to consider is adding an explicit top-level loop target in your method implementation.

Permalink

Not at all.

Not at all. I didn’t attempt it, but I have thought about it. I’m not sure how it would result in a situation much different from the one I described, or one that would be equal or better than Clojurescript. If you know Clojurescript you know Clojure, so you can write programs that compile to Java and C#. It’s a Lisp, where the syntax is represented entirely in terms of the language’s data structures, which makes writing macros and metaprogramming very easy. I don’t think I can achieve those things with a vanilla JS library.

Even if I gave up some of that, other people on my team or in open source would need to learn my library in order to work with me or understand the code I write. And even if people were willing to take the time to learn it, that knowledge would only be applicable in a very limited context (my projects). At best it would be another ramda or lodash/fp, which would seem to add to the problem I describe.

So I don’t think the solution lies within JS. I think you have to go above it.

Permalink

PurelyFunctional.tv Newsletter 231: Luna, Beautiful, Abstraction

Issue 231 – June 26, 2017

Hi friends,

Thanks so much for being on this journey with me. I couldn’t do it without you.

Please enjoy the issue.

Rock on!
Eric Normand <eric@purelyfunctional.tv>

PS Want to get this in your email? Subscribe!


The Most Beautiful Program Ever Written

William Byrd (from Mini Kanren fame) geeking out over the Lisp interpreter written in itself.


Separation of concerns

I was rereading this old post of mine, from back when I posted articles in the Clojure Gazette.


Stu Halloway on the Defn podcast

This is a great interview and worth a re-listen.


Clojure Newbie Guide

A bit terse, but this does cover a lot of the bases for things a newbie would want to know about the community.


Improving on Types: Specing a Java Library

Stu Halloway describes how to use Spec to select a library. There’s a lot of expert Clojure knowledge all the way through.


The Utopian UI Architect

I’m a big fan of Bret Victor and his mission to transform computing. I had never read this article.


Atoms, delays and side effects: a resource management idiom for Clojure

Dan Lebrero has been on fire with these articles. This one is about how to coordinate an effect among multiple threads.


The Sharp Edges of Leaky Abstraction

Mark Allen discusses the Law of Leaky Abstractions.


Luna

An interesting dynamic and visual functional language. I’m glad to see the artificial barriers crumble between typed and available-at-runtime languages.

Permalink

Copyright © 2009, Planet Clojure. No rights reserved.
Planet Clojure is maintained by Baishamapayan Ghose.
Clojure and the Clojure logo are Copyright © 2008-2009, Rich Hickey.
Theme by Brajeshwar.