0% found this document useful (0 votes)
156 views

ClojureDart Cheatsheet

This document provides a summary of key concepts for interacting between Clojure and Dart, including: - Object destructuring in Clojure can use :flds to mirror Dart - Dart supports optional parameters that can be positional or named - Dart packages can be required in Clojure namespaces by specifying a string instead of a symbol - Dart types can be prefixed by aliases to refer to types from imported packages - Dart supports enums, constructors, and nullability that Clojure must account for when interacting with Dart code - Dart has constants that Clojure must opt into or opt out of to correctly infer constant expressions

Uploaded by

dhaya
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
156 views

ClojureDart Cheatsheet

This document provides a summary of key concepts for interacting between Clojure and Dart, including: - Object destructuring in Clojure can use :flds to mirror Dart - Dart supports optional parameters that can be positional or named - Dart packages can be required in Clojure namespaces by specifying a string instead of a symbol - Dart types can be prefixed by aliases to refer to types from imported packages - Dart supports enums, constructors, and nullability that Clojure must account for when interacting with Dart code - Dart has constants that Clojure must opt into or opt out of to correctly infer constant expressions

Uploaded by

dhaya
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 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