I asked the question Lightweight data modeling vs traditional classes 
<https://programmers.stackexchange.com/questions/260309/lightweight-data-modeling-vs-traditional-classes>
 
on Programmers.StackExchange three days ago. I am happy I found this 
discussion, because the evil moderators at SE hate my question, and want to 
close it. As it was originally, the question was much longer than it is 
now, and I feel bad about throwing all what I wrote away, so I want to send 
it here.
I want to ask a follow-up question to [Q: Functional Programming vs. OOP](
https://programmers.stackexchange.com/questions/9730/functional-programming-vs-oop)
 
regarding the data representation.

To explain what I mean by "lightweight data representation", I'll quote 
from [a Mark Engelberg's blog](
http://programming-puzzler.blogspot.cz/2013/12/clojure-vs-scala.html)

> Just as one example, consider modeling a deck of cards. In Clojure,
> you'd be more likely to come up with a simple representation for a
> card, perhaps: [10 :spades]. Depending on the card game, you might
> choose to represent a face card as [:king :clubs] or [13 :clubs]. A
> deck would likely be modeled as just a sequence of cards, and all the
> built-in sequence functions would apply, for example, shuffle, take,
> drop, etc. Serializing the data (for example, if you want to keep a
> database tracking all the shuffled decks you've ever used in a given
> game) comes for free.
> 
> On the other hand, in Scala, you'd be more likely to create a card
> Class with a rank and suit field. The Suit class would be comprised of
> four case classes, because the philosophy is to enumerate all the
> possible suits as separate entities -- there's nothing in Scala like
> Clojure's convenient keywords. For the rank, you'd be steered towards
> representing all the ranks as integers. The possibility of
> representing face cards with a name would likely never occur to you,
> because it would be too complicated to go through the effort of
> defining the type of a rank to be a "integer or a class comprised of
> four case classes -- jack,queen,king,ace". For modeling the deck, you
> probably wouldn't say a Deck is-a sequence, because composition is
> favored over inheritance. So you'd probably have a Deck class which
> would contain a sequence of cards. This means that you'd have to
> reimplement methods like shuffle, take, and drop on your Deck class to
> turn around and dispatch those methods to the underlying sequence of
> cards. If you're not careful, years of object-oriented training might
> kick in and before you know it, you're representing the deck as a
> class where methods like shuffle, take, and drop destructively update
> the underlying sequence -- it feels so natural to do that once you've
> encapsulated the underlying sequence of cards in a class. If you want
> to serialize a deck, that's more code to write (although general
> "pickling" of a Scala object is an active area of research).
> 
> This example pretty much sums up what I prefer about Clojure. I like
> to tell people that a big part of what makes Clojure special is its
> **philosophy of lightweight data modeling**. It leads to delightfully
> simple systems. Scala remains deeply rooted in the OO philosophy,
> which all too often leads to an over-engineered muddle.

Lightweight data modeling is of course not limited to FP languages, 
although the ease of creating immutable values in many FP languages makes 
it very attractive there. [Peter Norvig's Python programming class](
https://www.udacity.com/course/cs212) on Udacity started by discussing card 
games and the representation he suggested for a card was a tuple. That is 
my second example to illustrate that lightweight data modeling is popular 
nowadays.

The example from an opposing camp which I've read somewhere illustrates the 
advantage of classes as a mechanism to deal with changing requirements in 
large systems. Imagine you've decided to represent prices in your system as 
some sort of arbitrary precision integer and only later realize that the 
system would be dealing with EUR as well as USD. Then you need to go back, 
create a class with an amount and currency field and change all the code 
that works with prices.

Then, there is this interesting debate in the Python world, of course not 
all is relevant, because Python does not embrace immutability

Stop writing classes, PyCon US 2012 
<https://news.ycombinator.com/item?id=3717715>

Start writing more classes, some blog 
<http://lucumr.pocoo.org/2013/2/13/moar-classes/>

Stop writing stupid classes 
<http://eev.ee/blog/2013/03/03/the-controller-pattern-is-awful-and-other-oo-heresy/>

Some more from the Clojure camp, this time by the creator himself in [the 
talk Simple Made Easy](http://www.infoq.com/presentations/Simple-Made-Easy).

@56:30 into the talk:

> Finally in this area. Information. It is simple. Right? The only thing
> you can possibly do with information is ruin it. Right? Don't do it.
> Right? Don't do this stuff. I mean. We got objects. Objects are made
> to like encapsulate I/O devices. So there is a screen, but I can't
> like touch the screen, so I have an object. There's the mouse. I can't
> touch the mouse so there's an object. Right? That's all they're good
> for. They were never supposed to be applied to information, we apply
> them to information. That's just wrong. It's wrong. I can now say it's
> wrong for a reason, right? It's wrong because it's complex. In
> particular, it ruins your ability to build generic data manipulation
> things. If you leave data alone, right, you can build things once that
> manipulate data. And you can reuse them all over the place. And you
> know they are right once and you're done. The other thing about it,
> which also applies to ORM is that it will tie your logic to
> representation things. […] So represent data as data, please. Start
> using maps and sets directly. Don't feel like I have to write a class
> now, 'cause I have a new piece of information. That's just silly.

Are there any other relevant arguments that have been made in this 
discussion besides what I've just tried to summarize?

Having in mind *the "expression problem" mentioned* in one of the answers 
to the original question, it seems to me that lightweight data 
representation is only suitable for small systems or isolated parts of 
large systems where the problem domain is well understood. If that is not 
the case, then we need to use algebraic data types or classes, each is 
extendable, but each in a different direction.

Finally I want to make the following comments about the previous 
discussion, mostly to prove I am not just posting heaps of text without 
reading what people said before me:

I don't know who is the outlier. The point is that Scala, for instance, has 
> explicit support to hide the distinction between accessing a value and 
> computing a value. The point is to support the uniform access principle. 
> http://en.wikipedia.org/wiki/Uniform_access_principle To my knowledge, 
> Clojure cannot do this.


Dart does that too. Every property access, even to globals, is a method 
call. It is pretty much the only new feature the language has (not counting 
.. method cascades, lambdas and not requiring everything to be in a class, 
which is all hardly new for somebody outside the Java world) and all talks 
that give Dart a pitch praise UAP, maybe because there is not much else to 
praise.

But there's nothing about the value of data-driven development that 
> requires data lookups and data computations to be so different.


Is calling a pure function on an immutable value a data access? I think it 
is. In my mind, 7+5 is a thing, 13, not a computation. A sufficiently smart 
compiler/interpreter may evaluate the access function at object creation 
and store all as a value {:fst 7 :snd 5 :sum 13} .

The good news is that if the community does start to see more value in 
> uniform access, achieving that is just a few macros away.


Implementing Uniform access principle as a macro is fine, the good thing is 
that it won't create the problem we know from Javascript OO libraries. "My 
UAP macro works differently than your UAP macro so instead of UA we are 
having NA (no access)".

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to