Curious (Clojure) Programmer Simplicity matters

Menu

  • Home
  • Archives
  • Tags
  • About
  • My Talks
  • Clojure Tip of the Day Screencast
  • (Open) Source
  • Weekly Bits & Pieces
  • RSS
June 9, 2022

Weekly Bits 12/2022 - Abstractions, Lisp in Small Pieces, lein repl vs JIT,

Table of Contents
  • Clojure
    • Feature flags
    • Eric Normand on Abstraction
    • Clojure (de-)serialization - java.sql.Timestamp
    • Clojure performance - lein repl vs clj
  • AWS & Cloud
    • Glob expressions in Cloudwatch Insights
  • Reading (Books)
    • Lisp in Small Pieces
  • MISC
    • 1Password CLI - sign in only if you are not already
  • Links

Some of the interesting things I did, learned, or found in the past week (16.5 - 22.5.2022).

Clojure

Feature flags

I found lambdaisland/pennon - a very simple Clojure library for feature flags.

Eric Normand on Abstraction

In Koppel’s abstractions, Eric refers to an article by James Koppel on abstraction. It’s very much worth reading but the core idea is that abstractions are mappings between a complex concrete world (like voltages), and a simple idealized one(like binary numbers).

468: Choice of abstraction matters,

  • a lecture by Dijkstra (Edsger W. Dijkstra - The Power of Counting Arguments) where he presents some river-crossing puzzles. One of the puzzles is the Wolf-Goat-Cabbage problem.

  • there can be a downside of choosing an abstraction: e.g. using :alpha :goat where :alpha can represent both wolf and cabbage - now you can’t have two alphas in the set and you need to decode that; you can also introduce errros

  • if you instead choose :wolf :goat :cabbage it’s straghtforward and you can keep them in the set (although you might need to examine more choices to find the right answer)

Clojure (de-)serialization - java.sql.Timestamp

From printing and reading date types. Here’s a demonstration how java.sql.Timestamp is special - it is deserialized as an instance of java.util.Date!.

https://github.com/jumarko/clojure-experiments/blob/master/src/clojure_experiments/compiler/reader-and-printer.clj#L15-L19

;; notice that java.sql.Timestamp is special in this regard
;; and serializaing and deserializing it again will return java.util.Date
;; see https://ask.clojure.org/index.php/11898/printing-and-reading-date-types
(type (deserialize (serialize (java.sql.Timestamp. 1))))
;; => java.util.Date

Clojure performance - lein repl vs clj

Ben Sless on Slack mentioned that lein repl turns off some JIT optimizations which in some cases yields significantly slower code execution.

I experimented with it a bit and found that leiningen adds the following JVM flags:

-XX:+TieredCompilation
-XX:TieredStopAtLevel=1

This means that the Tiered compilation stops at the first level - only the most basic optimizations performed by client compiler are applied.

In practice, this might lead to a big performance impact:

  • plain clojure

    clj
    
    user=> (System/getProperty "java.version")
    "17.0.2"
    
    user=> (time (reduce + (range 100000000)))
    "Elapsed time: 609.163893 msecs"
    4999999950000000
  • lein repl

    lein repl
    
    user=> (System/getProperty "java.version")
    "17.0.2"
    
    user=>  (time (reduce + (range 100000000)))
    "Elapsed time: 2808.390173 msecs"

AWS & Cloud

Glob expressions in Cloudwatch Insights

parse in Cloudwatch Insights supports glob expressions: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html

parse @message "[*] * The error was: *" as level, config, exception

This is easier to use than parse with regular expressions.

Reading (Books)

Lisp in Small Pieces

I almost finished the first chapter, did some exercises, had another fun pairing session, and worked hard to get ready for the second chapter.

I’d say the most important section is 1.6 about function execution environment.

The difference between lexical and dynamic binding demonstrated in 1.6.1 is also important although the dynamic binding felt like a tangent - worth exploration but not something we are going to focus on going forward.

I only skimmed section 1.6.2 Deep or Shallow Implementation because I don’t think shallow implementation is very useful (the cost of lookup is already minimal when using a hashmap to represent an environment).

In 1.7 Global Environment we have defined a handful of standard useful functions (aka "stdlib") such as list, cons, car, +, etc. We have defined them through a couple of macros definitial and defprimitive. I didn’t expect it but I got stuck on these macros for a few hours, mostly due to problems with symbol (auto-)resolution. With a lot of trial and error and using macroexpand I finally managed to make them work.

In 1.8 Starting the Interpreter, we implemented dead-simple interpreter/REPL, later extended in one of the exercises to support clean exit:

(defn repl1
  "Reads a single line from stdin, `evaluate`s it and prints the result to stdout.
  Returns the evaluated expression."
  []
  (-> (read) (evaluate env-global) (doto (prn))))

;; this is called `toplevel` in the book
(defn repl
  "`repl1` in a loop with support for a clean exit via `(end)`.
  To exit enter "
  ([]
   (println "Welcome to the REPL!")
   (println "You can evaluate forms one by one - they are read from stdin.")
   (println "When you are done, type (end)")
   (repl nil))
  ([last-ret]
   (if (= last-ret 'repl.exit)
     (println "Bye!")
     (recur (repl1)))))

You can find all my code here: https://github.com/jumarko/lisp-in-small-pieces/tree/main/clojure/src

MISC

1Password CLI - sign in only if you are not already

For things like using AWS MFA for AWS CLI I leverage 1password CLI. But it takes a while to sign in and I do not want to do it if I’m already logged in. Here’s a way to do it:

op account get > /dev/null || eval $(op signin) && echo "signed in"

Links

A quick recap of some of the links mentioned in this post:

  • My code for Lisp in Small Pieces

  • Eric Normand on Abstraction

    • 467: Koppel’s abstractions

    • 468: Choice of abstraction matters

      • Edsger W. Dijkstra - The Power of Counting Arguments

  • parse in Cloudwatch Insights supports glob expressions: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html

  • (Clojure) printing and reading date types: https://ask.clojure.org/index.php/11898/printing-and-reading-date-types

  • Ben Sless on Slack mentioned that lein repl turns off some JIT optimizations


Tags: clojure weekly-bits leiningen lisp-in-small-pieces performance abstraction

« Weekly Bits 13/2022 - Title Weekly Bits 11/2022 - Lisp in Small Pieces, Abstractions, Project Loom, and Fixing ring's redirects »

Copyright © 2025 Juraj Martinka

Powered by Cryogen | Free Website Template by Download Website Templates