When we have a multi-module project in Gradle we sometimes want to have dependencies, task configuration and other settings shared between the multiple modules. We can use the subprojects
or allprojects
blocks, but the downside is that it is not clear from the build script of the subproject where the configuration comes from. We must remember it is set from another build script, but there is no reference in the subproject to that connection. It is better to use a plugin with shared configuration and use that plugin in the subprojects. We call this a conventions plugin. This way it is explicitly visible in a subproject that the shared settings come from a plugin. Also it allows Gradle to optimize the build configuration.
Continue reading →
Clojure supports advanced destructure features. In a previous post we learned about destructuring maps, but we can also destructure vectors, list and sequences in Clojure using positional destructuring. We can define symbols for positions in the sequence to assign the value at a certain position to the symbol. The first symbol in the destructure vector gets the value of the first element in the sequence, the second symbol the value of the second element and so on. To get the remaining elements from the sequence without assigning them to specific symbols we can use &
followed by a symbol. Then all remaining elements are assigned as sequence the symbol. Finally we can use :as
to get the original vector, list or sequence.
The folowing examples show several destructure definitions for different type of collections and sequences:
Continue reading →
When we want to assign key values in a map to symbols we can use Clojure’s powerful destructure options. With destructuring a map we can use dense syntax to assign keys to new symbols. For example we can use that in a let
special form to assign symbols, but also for function parameters that are a map. When we use it for function parameters we can immediately assign keys to symbols we want to use in the function. Clojure provides a simple syntax to destructure a key value to a symbol using {symbol key}
syntax. The value of :key
will be assigned to symbol
. We can provide default values if a key is not set in the map using :or
followed by the symbol and default value. This is very useful if we know not all keys in a map will have values. Finally there is a shorthand syntax to assign keys to symbols with the same name as the key: :keys
. We must provide a vector to :keys
with the name of the keys, which will automatically assigned to symbols with the same name. To use this destructuring to its fullest the keys in the map must be keywords. We can use the keywordize-keys
function in the clojure.walk
namespace if we have a map with string keys and we want to transform them to keywords.
In the following example code we see several example of map destructuring:
Continue reading →
With the function distinct
we can remove duplicate elements from a collection. The function returns a lazy sequence when we use a collection argument. Without arguments the function returns a transducer. When we want to remove duplicates and we don’t need the lazy sequence result we could also turn a collection into a set with for example the set
or into
functions.
In the following example we use the distinct
function on several collections.
Continue reading →
The Clojure core namespace contains many functions. One of the functions is the dedupe
function. This function can remove consecutive duplicates from a collection and returns a lazy sequence where only one of the duplicates remain. It will not remove all duplicate elements from the collection, but only when the element is directly followed by a duplicate element. The function returns a transducer when no argument is given.
In the following code sample we use the dedupe
function on several collections:
Continue reading →
Accessing Java from Clojure is easy. With the dot (.
) special form we can invoke for example methods from a Java class or instance. If we want to invoke several methods together where the return value from one method is used to invoke the next method (method chaining) we can use the ..
macro. The macro will expand into a nested expression with the .
forms.
In the following example we see how to use the ..
macro and how we can achieve the same result using nested .
expressions and by using the thread first macro:
Continue reading →
Nowadays, we usually work with frameworks when we want to set up a frontend application. We enter the terminal and enter something like ng new my-app
or npx create-react-app my-app
. The cli works it’s magic and sets up an entire application with a whole lot of stuff included. We’re good to go. But what if you just want to build something simple? What if you want to build an app that simply doesn’t have a lot of logic, and doesn’t need a complete framework, like a portfolio website. Or, what if you want to challenge yourself and see if you can build something worthwhile without a framework?
Continue reading →
Sometimes we want to invoke Java methods from our Clojure code. If the Java method accepts a variable arguments (varargs) parameter and we want to invoke the method from Clojure we must pass an array as argument. To create an array in Clojure we can use several functions. The to-array
function will transform a collection to an Object[]
type. For primitive type arrays we can use for example int-array
to get a int[]
array. The function into-array
is the most flexible function. This function accepts a sequence argument and optionally the class type of the resulting array. Once we have the array we can use it as argument value for the varargs parameter of the Java method we want to invoke.
In the following example we use into-array
, to-array
and short-array
to invoke a Java method with varargs parameter and see how we can build different array types:
Continue reading →
The Java Stream API has many useful methods. If we want to partition a stream of objects by a given predicate we can use the partitioningBy()
method from the java.util.stream.Collectors
package. We must use this method in the collect()
method of the stream. The result is a Map
with the keys true
and false
. The objects from the stream that are true for the predicate will end up in the true
value list and if the result of the predicate is false
the value will end up in the list of values for the false
key. The partitionBy
method accepts a collector as second parameter. This collector will be applied to the values before they are put in the true
or false
keys in the result.
In the following example we use the partitioningBy
method with different streams:
Continue reading →