ClojureDart Cheatsheet

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 2

ClojureDart :flds, Object destructuring Optional params (named or not)

:keys, :strs and :syms are proud to introduce :flds Sometimes interop requires implementing a function
Cheatsheet for Clojurists
their object-destructuring counterpart.
or method taking Dart optional parameters.

CLI (let [{:flds [height width]} size] …) is [a b c .d .e] 3 positional parameters and two
clj -M:cljd init equivalent to:
named ones: d and e.

clj -M:cljd flutter # press RET to restart (let [height (.-height size) [a b c ... d e] 5 positional parameters, 3 xed
clj -M:cljd compile width (.-width size)] and 2 optional.

clj -M:cljd clean # when in panic …) [.a 42 .e] two named parameters a and b where a
clj -M:cljd upgrade # stay current w/ CLJD
defaults to 42.

Constructors
Using Dart packages In Dart, constructors do not always allocate, they can [... a 42 b] 2 optional positional parameters a and
In the ns form, :require as usual but with a string return existing instances. That’s why there’s no new b where a defaults to 42.

instead of a symbol:
nor trailing . (dot) in ClojureDart.
 Enums
(ns my.project Default constructors are called with classes in
(:require
Enums values are just static properties on types.

function position.

["package:flutter/material.dart" :as m])) e.g. m/TextAlign.left

(StringBuffer "hello")
Types and aliases Named constructors are called like static methods.
Consts and const opt-out
Unlike Clojure/JVM, types can be pre xed by an (List/empty .growable true) Dart has consts: deduplicated compile-time constant
alias. m/ElevatedButton refers to ElevatedButton in expressions in which const constructors may
Understanding Dart signatures participate. It’s an opt-in mechanism.

the package aliased by m.


writeAll(Iterable objects,
[String separator = ""])
ClojureDart maximally infers const expressions. In
Types and nullability some rare occasion (like creating a sentinel or a token)
One (positional) parameter objects of type Iterable,
In ClojureDart, ^String x implies x can’t be nil.
you have to tag the expression as unique: ^:unique
one optional positional parameter separator of type
Use ^String? x to allow for nil.
(Object); otherwise you always get the same
String whose default value is "".

instance.

Parametrized types RegExp(String source,


{bool multiLine = false, Creating classes
Unlike Clojure/JVM, generics do exist at runtime so
bool caseSensitive = true})
ClojureDart has to deal with them. reify, deftype and defrecord gets new powers.

One (positional) parameter source of type String,


Dart ClojureDart two optional named bool parameters multiLine Creating classes: :extends
List List (defaults to false) and caseSensitive (defaults to
List<Map> #/(List Map)
Extending classes, even abstract ones!
true).
The :extends option speci es a class or a
List?<Map> #/(List? Map)
List<Map?> #/(List Map?) any(bool test(E element)) constructor call (the super constructor call).

#/(List Map) is just the List symbol with some


One (positional) parameter: test, a function of one
metadata! Thus you can write ^#/(List Map) x.
parameter element of type E (itself a type parameter) Creating classes: mixins
returning a bool.
Mixin types must be tagged with ^:mixin.

Property access
Instance get (.-prop obj), set (.-prop! obj x) or
Named arguments Creating classes: operators
(set! (.-prop obj) x)
Some Dart functions and methods expect named Dart supports operators overloading but not all
arguments (argname: 42 in Dart), in ClojureDart operators make valid Clojure symbol ([]= for
Static m/Colors.purple, this can even be chained m/
it’s .argname 42.
example). That’s why it’s valid ClojureDart to have
Colors.purple.shade900 or even terminated with a
(m/Text "Hello world" strings as methods names.

method call

.maxLines 2 (. list "[]=" i 42) ; list[i] = 42
(m/Colors.purple.shade900.withAlpha 128).
.softWrap true It’s also valid to use strings-as-names when
.overflow m/TextOverflow.fade) implementing operator overloads as part of a class
de nition.

fi






fi


fi

fi

Getters/Setters .child-threading Cells


Dart properties are not all elds: most are getters/ Inside a “widget-body”, expressions are threaded Great for maintaining and reusing derived state; tip: try
setters. However they behave like elds, you get them through the named param .child:
to share them via inherited bindings (see :bind) rather
(.-prop obj) and you set them (set! (.-prop (f/widget than function arguments.
obj) 42) or (.-prop! obj 42).
m/Center f/$ (“cache”) creates a cell.
Getters and setters are de ned as regular methods, in (m/Text "hello"))
(f/$ expr), like a spreadsheet cell, updates its
the body of a reify/deftype/defrecord. A getter is equivalent to:

value each time a dependency changes.

expects one parameters [this] while a setter (m/Center .child (m/Text "hello"))
Dependencies can be any watchable including other
expects two [this v].
When the two expressions are separated by a dotted
cells. Dependencies are read using f/<! (“take”). f/
If the property is de ned in a parent class or interface, symbol, this symbol is used to thread them:

<! can be used in any function called directly or


you don’t need anything special. If the property is m/MaterialApp
indirectly from a cell.

newly introduced by the type you need to tag the .home


m/Scaffold :managed directive
method name with ^:getter or ^:setter.
.body
Automatic lifecycle management for *Controllers
(m/Text "Don't stop it now!”)
and the like.
:let directive :managed takes a bindings vector like :let but
(f/widget :let [some bindings] …) rewrites as expressions must produce objects in needs of being
cljd.flutter: more Flutter, (let [some bindings] (f/widget …)).
disposed (using the .dispose method by default).

less clutter! :key directive :bind directive


Keys are primordial for recognizing sibling widgets in Dynamic binding but along the widgets tree, not the
cljd.flutter is not a framework. It’s an utility lib to a list (or anywhere a .children argument is expected) call tree. Inherited bindings in Flutter speak.
cut down on the boilerplate and thus to make Flutter updates after updates without losing or mixing state.
:bind {:k v} establishes an inherited binding
more pleasing to Clojurists palates. Bon Appétit!
It will wrap its value inside a ValueKey so that you from :k to v visible from all descendants.

don’t have to.

It’s dangerous to go alone! :get directive


Require this.
:watch directive :get [:k1 :k2] retrieves values bound to :k1
[cljd.flutter :as f] Or how to react to IO and state. and :k2 via :bind.

[“package:flutter/material.dart” :as m]
:watch takes a bindings vector. Unlike :let, :get [m/Navigator] retrieves instance returned by
f/run [& widget-body] expressions must be watchable and binding forms (m/Navigator.of context)

Called from main, starts the application (a Widget). Its will be successively bound to values produced by
their watchable.
:context directive
body is interpreted as per f/widget. Makes the root For when Flutter asks for more context.
of the app reload-friendly.
:watch [v an-atom]
(m/Text (str v)) :context ctx binds ctx to a BuildContext instance.

f/widget [& widget-body] When an-atom changes, everything after :watch will
:vsync directive
Mother of all macros. Evaluates to a Widget.
 update with v bound to the current value of an-atom.

Have you ever chased an electron beam across a


Its body is made of interleaved expressions and
directives.
watchables phosphor screen?
nil, atoms, cells, Streams, Futures, Listenables and :vsync clock binds clock to a TickerProvider,
Directives are always keywords followed by one
ValueListenables and any extension of the generally required by animations.

other form. Directives range from the mundane :let


Subscribable protocol.

to the speci c :vsync.

Expressions are .child-threaded.

fi

fi

fi
fi

fi

You might also like