avatar

Enyert Vinas

Posted on 26th April 2022

ClojureDart: Aim your darts at the right target!

news-paper Clojure | Software Development |

It’s a fact that Clojure is an awesome language, it’s gaining popularity and it’s offering new libraries at an impressive rate. But like any other technology, our favorite language has its own limits.

For this reason, the community is always open to expanding the Clojure language, and sometimes the way to accomplish this objective is through the integration with other languages.

This time we want to present a good example of this approach, ClojureDart!

Dart

To start with all this journey I think it’s needed to start with a brief introduction to Dart. It’s a type-safe language because it uses static type checking.

Dart offers sound null safety, this means protection against null values but you can decide when to do that. For example, when you are trying to access a HashMap it is possible to get a null value if you provide a non-existent key. So you will get an error if you try to compile the source unless you specify the “confidence” about the existence of the key.

Dart can be used for multiple purposes such as server applications, desktop, browser, and mobile applications. If you want to learn more about Dart, I recommend this course. It’s super complete, simple, and free!

Please notice that I mentioned that we can create mobile applications with Dart. I am repeating this because I want to present to you a framework named Flutter.

Flutter

Flutter is an SDK(Software Development Kit) and framework created by Google with a focus on building and deployment of mobile, web, and desktop applications. This framework uses Dart as a primary language. Flutter is modular, so the developers will have to build their applications composing several elements named widgets.

Widgets can be shared between different applications and they provide specific themes and behaviors that can be customized depending on the parameters exposed. For this purpose, widgets use “named parameters”, a feature that belongs to the Dart language.

Now that we have an introduction to Dart and Flutter we can talk about our rock star, ClojureDart!

ClojureDart

Using the definition from Github:

ClojureDart is a port of the Clojure language to Dart.

https://github.com/Tensegritics/ClojureDart

I started this section with this definition because it’s simple and almost auto-explained. ClojureDart provides different mechanisms to interact with Dart using Clojure.

Now think about the relationship between all the ideas exposed until now. First, we had something like this:

Relationship between Dart and Flutter

This is great because with Dart language we can easily create web and mobile applications. But what if we produce Dart code using Clojure, our favorite language? Just like this:

Add Clojure to the flow!

Well, let me tell you something: It is possible! And it’s awesome!

Baptiste Dupuch and Christophe Grand in conjunction with other collaborators bring ClojureDart to us!

Call to action: Super Counter Application!

After reading some of the code from ClojureDart and playing a little bit with the basic examples, I want to share my experience with you with the traditional counter application.

This application contains a top bar with a title, a body text showing the information of a counter, and a ‘+’ button that increment the counter. It’s a super easy example but I think it demonstrates the possibility to create a mobile application using ClojureDart.

Installation and configuration

To follow this example, you will need to install and configure Dart, Flutter, and Clojure. For Dart and Flutter please follow this course (at least the installation & configuration part). For Clojure, I assume you are familiar with the process but you can follow this link in case you are new to the language.

Project setup

The project setup is really easy by using a deps.edn as follows:

{:paths ["src"] ;; Paths to your *cljd files
 :deps {org.clojure/clojure {:mvn/version "1.10.1"}
        tensegritics/clojuredart
        {:git/url "git@github.com:tensegritics/ClojureDart.git"
         :sha "b49677deaee9c2cc46c165975004d297fe5cabc8"}}}

The structure of this project (ignoring the data that will be created later) will be as follows:

Where our main.cljd file will be compiled to create the output *.dart file. But first, we need to run the following command inside our helloflutter folder:

clj -M -m cljd.build init acme.main

This command will use the init associated command with the init-project function. To be more concise, this will prepare part of the environment to run our project using flutter as a default option.

The code

Our code will live in the flexiana.main namespace and will look like follows:

(ns flexiana.main
  (:require ["package:flutter/material.dart" :as material]
            ["package:flutter/widgets.dart" :as widgets]
            ["package:flutter/painting.dart" :as painting]
            [cljd.flutter.alpha :as f]))

(defn main []
  (material/runApp
   (material/MaterialApp.
    :title "Welcome to ClojureDart"
    :theme (material/ThemeData. :primarySwatch material.Colors/amber)
    :home (f/widget
           :state [counter 0]
           (material/Scaffold.
            :appBar (material/AppBar.
                     :title (widgets/Text. "Welcome to ClojureDart"))
            :body (widgets/Center.
                   :child (widgets/Text. (str "Counter info: " @counter)
                                         :style (painting/TextStyle.
                                                 :color material.Colors/grey
                                                 :fontSize 32.0)))
            :floatingActionButton (material/FloatingActionButton.
                                   :child (material/Icon.
                                           material.Icons/add)
                                   :onPressed (fn [] (swap! counter inc))))))))

If you are familiar with Clojure and Flutter this code will look familiar to you, in other cases I recommend you to review the documentation. In both cases, I am sure you noticed that we are creating a material application using the composition of a bunch of widgets.

Running the application

If you want to run the application, please run the following command:

clj -M -m cljd.build flutter

This will run the flutter runtime and probably will find the devices installed in your machine (be patient here). After this, you will see something similar to this on your device:

Super Counter Application

And congratulations, the Super Counter Application is running!

Benefits of the language integration

With this post, I wanted to share with you my experience playing with ClojureDart. I think this is bringing the opportunity to develop mobile applications, so it helps to expand the domain of Clojure ecosystem. I want to play a little bit more with this (e.g. trying Flame Engine), so I will let you know if I can create something interesting in the near future.

Thank you for your time reading the post and happy hacking! 🙂