I feel the other answers to your comment failed to really illustrate the property.
The history paper Rich Hickey wrote alludes to this throughout it all.
Basically, data is central, everything about the language makes modeling data simple, first class, and non-ceremonious. You can take the data your domain relies on, and use it directly, in the same structure the domain structures it, no abstraction needed, no mappings, no adapters, just straight up.
It's really hard to communicate what a data centric approach feels like. But I will try. Keep in mind, there are a multitude of details and features across the entire language which all focus on this data centric approach, and they all serve a role and come together to create this property. It is not any one feature, but really the sum of all of them which enable the property to surface. I will mention only a few to give an idea.
#1 Flexible data representation
Imagine we have a business, and they have product listings, and their products are uniquely identified by vendor and name. In pseudo-model we would have:
vendor+name -> product
Now in Clojure we can model this as:
{[vendor, name] product}
That's it. This will now be the data-structure we will use. We're now going to write a bunch of operations over it which map to the operations the business does in its day to day with regards to its product listing.
Think about how you'd model that in other languages. In JavaScript, which also has a pretty flexible data model, this won't work, because keys to JS Objects cannot be a composite. One would need to have a string encoding and some mapping from the input to the string encoded variant and back, such as:
{"vendor_name": product}
In Java, one would refrain from using a Map<List, Product>, and instead would model this as classes. Maybe you'd have:
public class Listing {
String vendor;
String name;
Product product;
}
List<Listing> listings;
But now you can't easily lookup for a product by vendor+name. So maybe one would instead do:
public class ProductId {
String vendor;
String name;
}
Map<ProductId, Product> listings;
Except it turns out that for certain products, but not all, the business also distinguishes them by manufactured year. And some other are distinguished in addition not by manufactured year, but color. In Clojure you'd just have:
public class ProductId {
String vendor;
String name;
String color;
String manufactured-year;
}
Map<ProductId, Product> listings;
Where color or manufactured-year can be null.
And maybe you don't find the Java one that bad quite yet. So let's now talk about a second data centric feature:
#2 Value semantics
It turns out, in Java, the above code does not work. If the business says, find me the product Kraft MacNCheese, you might be tempted to do:
ProductId productId = new ProductId("Kraft", "MacNCheese");
listings.get(productId);
But the productId you created is not equal to the productId of equal value which is currently stored in your Map. Two objects in Java are equal if they are the same object, not if they have the same value. In Clojure:
(get listings ["Kraft", "MacNCheese"])
That's it. In Clojure, things of the same logical value are equal by default. As such, Clojure has value semantics. Or in other words, equal data is equal, as it should be in my opinion.
#3 Data is same in memory and out
So we've come to the point where we want to export our listings. In Clojure we'd do:
(spit "/home/user/listings/my-listings" listings)
That's it. And when the user wants to import listings:
Because all data in Clojure can be serialized and deserialized as is by default. This gives us back our exact listings data-structure that we had.
#n
And like I said, there's many more such little features all thought of from a data centric perspective. When you add them all up, you start to realize everything is just data needed to be manipulated from one shape to another, and moved from one place to another.
In Java you can (and should) implement equality semantics however you want for Objects by implementing equals/hashCode. If you just want value semantics you can use a record type, which works just like the Clojure example.
The history paper Rich Hickey wrote alludes to this throughout it all.
Basically, data is central, everything about the language makes modeling data simple, first class, and non-ceremonious. You can take the data your domain relies on, and use it directly, in the same structure the domain structures it, no abstraction needed, no mappings, no adapters, just straight up.
It's really hard to communicate what a data centric approach feels like. But I will try. Keep in mind, there are a multitude of details and features across the entire language which all focus on this data centric approach, and they all serve a role and come together to create this property. It is not any one feature, but really the sum of all of them which enable the property to surface. I will mention only a few to give an idea.
#1 Flexible data representation
Imagine we have a business, and they have product listings, and their products are uniquely identified by vendor and name. In pseudo-model we would have:
Now in Clojure we can model this as: That's it. This will now be the data-structure we will use. We're now going to write a bunch of operations over it which map to the operations the business does in its day to day with regards to its product listing.Think about how you'd model that in other languages. In JavaScript, which also has a pretty flexible data model, this won't work, because keys to JS Objects cannot be a composite. One would need to have a string encoding and some mapping from the input to the string encoded variant and back, such as:
In Java, one would refrain from using a Map<List, Product>, and instead would model this as classes. Maybe you'd have: But now you can't easily lookup for a product by vendor+name. So maybe one would instead do: Except it turns out that for certain products, but not all, the business also distinguishes them by manufactured year. And some other are distinguished in addition not by manufactured year, but color. In Clojure you'd just have: In Java you'd now have: Where color or manufactured-year can be null.And maybe you don't find the Java one that bad quite yet. So let's now talk about a second data centric feature:
#2 Value semantics
It turns out, in Java, the above code does not work. If the business says, find me the product Kraft MacNCheese, you might be tempted to do:
But the productId you created is not equal to the productId of equal value which is currently stored in your Map. Two objects in Java are equal if they are the same object, not if they have the same value. In Clojure: That's it. In Clojure, things of the same logical value are equal by default. As such, Clojure has value semantics. Or in other words, equal data is equal, as it should be in my opinion.#3 Data is same in memory and out
So we've come to the point where we want to export our listings. In Clojure we'd do:
That's it. And when the user wants to import listings: Because all data in Clojure can be serialized and deserialized as is by default. This gives us back our exact listings data-structure that we had.#n
And like I said, there's many more such little features all thought of from a data centric perspective. When you add them all up, you start to realize everything is just data needed to be manipulated from one shape to another, and moved from one place to another.