Data is the core of all computer application, an information system basically receives information as input, executes operations and produces some output. Data is the core of computation, we execute operations using data, and as programmers we need to have ways of represent data at computer-level.
With this requirement, engineers and computer language hackers, created a way of represent data at software level classifying them in different types, and this type will represent a range of possible data and the way that it will behave when dealing with hardware.
All programming languages has a set of datatypes to deal with basic data, and imagine a language without them is almost impossible, Clojure of course has set of datatypes.
This post can look kind of boring but it’s necessary to study it before we start learning about functions in the next posts. It’ll do my best to this post don’t look boring and be short.
As a hosted language on JVM, most of its datatypes are from Java, and as we know, its heavy-tested for more 20 years, with excellent performance and interoperability, as we will see, Clojure strings are
java.lang.Strings and so on.
To check type of something in Clojure, just use the function
type, let’s start exploring with numbers, Clojure has it’s integer numbers that we already used in our journey when dealing with arithmetical operations:
=> (type 1) java.lang.Long
As we see, the type is mapped to a Java type (remember that Clojure is build on top of JVM), other common types behave like this:
=> (type "Hello String") java.lang.String => (type true) java.lang.Boolean => (type 42.42) java.lang.Double
As supposed, you can use
string to represent text,
boolean to represent true/false and
double to represent fractional numbers.
Most of languages includes a
float type, but as you should know, floats is not good enough, so, doubles are default in Clojure.
=> (type (+ 41.0 1.0)) java.lang.Double
floats are not banned at all, and Clojure has it, but it’s not the default, if you want to use it, you need to make a type conversion:
=> (type (float (+ 41.0 1.0))) java.lang.Float
Just to keep talking about math, Clojure has a type that is not common on most languages, it’s called
ratio that is useful to represent fractions:
=> (type 1/3) clojure.lang.Ratio
And as we already seen, we represent integer numbers with integer type:
=> (type 1) java.lang.Long
We can do mathematical operations on number as expected, just remember to use the polish notation, as we see in the last post.
=> (- 52 10) 42
One of the most important things to note here, is that if one number is fractional, the result is fractional, but you can do operations with integers and doubles interacting.
=> (- 52.0 10) 42.0
You can represent strings in Clojure just putting any text inside double quotes:
=> (type "I'm a text") java.lang.String
With the function
str you can convert almost everything in String, just try:
=> (type (str 1)) java.lang.String
Clojure has it
character type too, just type
\ before a single char:
=> (type \t) java.lang.Character
Logical values are represent by pure
false, no complexity here!
user=> (type true) java.lang.Boolean user=> (type false) java.lang.Boolean
And do logical operations with it too:
=> (and false false) false => (and true true) true => (or false true) true => (not true) false
In Clojure we only have two false values
nil that we will see next.
Keyword is a difficult topic to explain, folks coming from
lisp already know what I’m talking about. They look like string, but aren’t string, but are dedicated to be used as identifiers, they are just themselves, and you common will see as a map key for example.
They start with
: fallowed by a text:
=> (type :keyword) clojure.lang.Keyword
On the next post we’ll see more about
keyword when dealing with maps.
Symbols usually refers to something else, like functions, values. During the eval process they are evaluated to the value that its referring. To better understand it, let’s do and example.
We define a variable called
hello, with the
String “Hello Otavio”:
=> (def hello "Hello Otavio") #'user/hello
Now if we just print the
hello, as expected it will the string binded.
=> (println hello) "Hello Otavio"
And if we check the type of
=> (type hello) java.lang.String
It will return the type of what is binded to
hello and not the type of it, this occurs because evaluator first eval
hello and look for what is binded, before call
type. To check the true type of
hello we need to delay the evaluation as we saw in the last post:
=> (type 'hello) clojure.lang.Symbol
And that is our symbol. We already used a lot of symbols in this post, other example is the functions that we used:
=> (type 'println) clojure.lang.Symbol => (type '+) clojure.lang.Symbol => (type '-) clojure.lang.Symbol
As we will see in future, symbols can have a namespace separated from the name by forward slash.
Regex has its own datatype in Clojure too, to represent a regex just use a hash fallowed by a string:
=> (type #"regex") java.util.regex.Pattern
And with no surprise we will have a java datatype
And Finally…The emptiness, the void, the villain!
We’re talking about
nil, the value that represent nothing, the emptiness. For those who already code something, you probably know it, in some languages are called
None, it can be called a billion dollar mistake (watch this excellent talk anyway).
The rule is simple,
nil is type
nil and to represent
nil just type
=> (type nil) nil
On the next post we will see the collections, and understand each one and its use cases, for now to don’t extend this post we’ll finish here.
As a nice exercise for this post, check Clojure cheatsheet and you’ll see nice functions to deal with these datatypes.
Clojure has simple datatypes, and a uncommon datatype called
ratio, one of the interesting things its that Clojure uses
Double by default, so we avoid to use Floats.
If you have any questions that I can help you with, please ask! Send an email (otaviopvaladares at gmail.com), pm me on my Twitter or comment on this post!