14 comments

[ 3.5 ms ] story [ 41.2 ms ] thread
This is a good talk. It's cool to see a brief history of CLU as given by Liskov herself. However, there's a problem I see recurring in our field, even from respected sages like Liskov: programmers are willing to establish and vocalize an opinion on technologies they don't understand (Python and Haskell in this case). Is that pervasive in other fields as well? Why is that?
are you talking about her comment that Python has no data abstraction? Even I found that odd, maybe she was only talking about the lack of static types as opposed to java, c# which are "expert languages"
I think the point is that data abstraction in python is just a suggestion. If you follow convention, things can be abstracted to an extent. But there is nothing that enforces these abstractions on a user; you are not bound to operate only within a constrained context. Also, certain types of abstractions aren't possible in python because of the lack of interfaces.
Be careful with criticizing an obviously smart person like this based on a side comment you didn't had a chance to ask her to elaborate upon. I think with Python she meant things like Python not having real private variables or methods and not having real explicit interfaces, which I guess makes it pretty correct to say it doesn't have data abstraction.
Lack of private variables I can see criticism for. Lack of explicit interfaces seems to be a side effect of being untyped. That doesn't mean it doesn't have data abstraction -- at that point you'd also have to say that Scheme doesn't have data abstraction, yet SICP has a whole chapter dedicated to that topic!

I don't mean to criticize just Liskov. It seems to be a "feature" of a great deal of obviously smart people in our field, as well as some less obviously smart people. I don't get it.

Scheme doesn't have data abstraction in the sense Liskov's CLU had it for example, you can try to roll it yourself like SICP does, but it is not the same as having it as a language feature. Also interfaces can still be useful in an untyped language and there has been discussion of their inclusion in Python, see a good discussion here (some of the problems mentioned would apply to Scheme just as well I think):

http://www.python.org/dev/peps/pep-0245/

I am not invalidating your observation in general, to the contrary, I just don't agree Liskov is to blame of this here.

Ah, I see what you mean. Thanks for clarifying for me.
I've seen exactly what she describes with respect to Python.

Building large systems in Python requires a lot of discipline becuase it is so easy to violate sound engineering practices in this language. People come out of school without an understanding of how to build large systems and just throw code in until the thing becomes a large sphagetti mess. That is something that I think is unique to our field. I don't see civil engineers ignoring all engineering practices in stuff they build after they come out of school. You don't see them build bridges out of unsuitable materials or in unsound ways because it's "easier". It's not perceived that anyone with or without any knowledge can throw a few pieces of metal together and build a bridge...

> Building large systems in Python requires a lot of discipline becuase it is so easy to violate sound engineering practices in this language. People come out of school without an understanding of how to build large systems and just throw code in until the thing becomes a large sphagetti mess.

I posit that it's the same with any language. I've seen messy Java codebases and messy C++ codebases. I haven't read as much C# as I'd like, but I'm willing to bet it's the same story with those codebases. Python has a very similar object model to all of those languages with the exception that it's untyped.

Not in my experience. Python gives you complete control over object's internals with no real protection mechansim and this is very often abused. Duck typing is abused. Compilers give you some compile time guarantees that you don't get in Python. Not to mention eval(). Monkey patching. You can only pass by reference, not by value, again a big problem. Side effects galore.

I enjoy coding in Python and I've used it on and off for small things over many years but since getting involved in a project which has 100klocs of Python I've become pretty convinced it's a poor choice for this sort of scale.

Reading statically typed code you know what types the different objects are. In Python, no clue. This can be somewhat mitigated through documentation (e.g. see Google's Python style guide).

Want to find all the places a variable, or a class, or a function are used? You're out of luck. Good luck refactoring that bowl of spaghetti.

Yet another factor is that there a lot of people who have built very large systems in other languages (C/C++/Java/C# etc.) so the knowledge of how to manage that is more accessible.

A brief summary:

* Nowadays, we have the concept of interfaces to achieve modularity and local reasoning

* Liskov's initial contribution: partition global variables, require functions to only use variables in their partition or call functions in other partitions.

* Use data abstraction as a methodology (later on, use object orientation as the target of that methodology)

* She created CLU to communicate some of these abstractions to programmers: 1. Procedures are attached to types, not objects, 2. Parametric polymorphism: if quantification is needed, use structural subtyping, essentially, 3. For loops: use iterators with state stored on the stack (generators)

* When looking at object orientation in this context, she found that inheritance was widely used, both for interface/implementation and for type hierarchies. In both cases, semantics are important, even if two objects implement the same methods by name/types. Came up with Liskov substitution principle.

* Trends today: one of the issues with e.g. Java, C# is that they're not great for beginners who are forced to work around crufty abstractions (public static void main) without having the experience to know how to generally use those abstractions. On the other hand, Python is great for beginners but (according to Liskov) doesn't have great data abstraction for large-scale software engineering.

* Some perceived tradeoffs in a language that is good for both beginners and experts: 1. Ease of use vs expressive power, 2. Readability vs writeability (Liskov is worried about too much focus on the latter), 3. Modularity and abstraction, 4. Powerful abstraction matters, 5. State matters (see below)

* Finally, for massively parallel computers: how to do programming methodology?

That's what I thought to write down. I also thought to take a more precise transcript of her comments on Haskell:

> My final thing, which is in some sense aimed at Haskell, is that state matters. So, mostly computer programs are about managing state. And, although I am very sympathetic with the desire to keep most of your program immutable, because it's much easier to reason about correctness if you aren't doing modifications, a major part of your program is going to be concerned with state, and it has to be done in a simple way. It can't be complicated, it can't be hard to understand.

State is one of the most important (and sometimes annoying) things you deal with in Haskell when writing large programs. However, is it really better to sweep it under the rug and muddy semantics in the name of simplicity? One might merely just be pushing essential complexity to where it is harder to reason about.

I think the idea behind immutability is as follows.

Given X, we are completely comfortable with applying functions to X which take it from its current domain to a different one. These functions are composable.

f: X -> Y g: Y -> Z g . f : X -> Z

The "state" is transforming from one operation to another. The TWO tricky parts are how the initial state is populated, and how the state is presented to the enduser.

Good programming practices involve isolating these two endpoints from the code logic that does this change anyway. As I see it, Haskellers will have two "dirty" modules which handle I/O with monads, and a lot of pure modules that are very easy to reason about. However, doing this requires discipline and employing a certain coding style that many are not used to. Having worked with Haskell a lot, my programming style in other languages has improved a fair bit, and I intend to revisit Haskell for possible production use in the near future.

I feel very strongly that my understanding of state has both improved and become far simpler after programming intensely in Haskell for a long while. State in mutable languages is just too big to have a meaningful way to think about it on its own. Much of my Hs code lives in the state monad today, but I am never at a loss as to what that means exactly.
She gave this talk at my university, and was an engaging speaker. I was pleasantly surprised at the turnout, especially considering that the timing was strange.