Hacker News new | past | comments | ask | show | jobs | submit login
The Two Things about Computer Programming (pastiche.org)
138 points by avk on Nov 13, 2010 | hide | past | favorite | 90 comments



The computer will always do exactly what you tell it to.

With the obligatory footnote: "Unless you get into multithreading - then all bets are off." ;-)


Even if you multithread, it will still do exactly what you tell it to. It's just that it becomes even easier to tell it the wrong thing. ;-)


Multithreading sacrifices determinism. So, regardless of what you tell it you can't make any claims of exactness about what it's doing.


The computer is still deterministic, but somebody lower in the technology stack doesn't want to completely define its behavior.


Not so fast. You can still get nondeterministic behavior with things like thermal effects (think temperature affecting clock speed affecting relative timing between threads running on different processors)


You're right.

However, from the perspective of the programmer it is non-deterministic. It only becomes deterministic when it is coupled with a particular scheduler and dispatcher. Most programmers strive to write cross platform code.


> Most programmers strive to write cross platform code.

On what planet? Surely not this one, as most programs are very tightly coupled to particular operating systems.


Rude, but whatever... you might be right.

Regardless, a future version of any single platform could include changes to the scheduler and/or dispatcher.


Hm, sorry, didn't mean to be.


If it's non-deterministic, you're not doing it right.


That's false. If you're doing it "right" then it will produce the same functional output for all of the possible execution paths. That doesn't make it deterministic.


Perhaps you want it to be non-deterministic? E.g. Monte-Carlo-simulation or genetic algorithm with a hardware random-number generator.


The programmer is still allowed to specify operations to perform as well as restrictions on the order in which the operations are performed. Not fully specifying what to do just gives the computer more options to pick from -- it will still pick one of those options.


it will still pick one of those options

which is the part that gets rid of the "does what you tell it" bit, since now it's doing what it thinks it should, which might not be very consistent or easily determinable because minor variations during a race can produce wildly differing results.


If I tell someone, "bring me a sandwich or a bowl of chili," and the person brings me a bowl of chili, that person has done exactly what I told them to do.


What if they get bored waiting at the counter in the cafe and come back empty-handed? 'Cos that's what can happen as soon as IO is allowed into the picture; particularly so with network IO.


In that case you probably said "get me a bowl of chili if you can get served in a minute, otherwise don't bother". Or at least it was implicit.


The problem is that combining this with multithreading makes for a combinatorial explosion of possible states that you might have to deal with. It's just not feasible to exhaustively specify everything., and leaving things implicit means that you're expecting the computer to do things you haven't told it to do.


Sure, there is complexity. It's easy to make assumptions or forget real-world details too. But you DID tell it to time-out, because that's how the I/O library is specified.


The more pernicious problem is when they don't come back at all, having deadlocked.


True, but my point is still valid. When you start a thread, you're saying "do this these tasks in whatever order is most convenient for you". And the computer does just that.


If you're using threads you told it to be non deterministic. So it's still doing what you told it to.


It's still deterministic; just not by you: by the kernel.


Philosophically, it's deterministic. In engineering terms, it's non-deterministic from the perspective of the application programmer.


Philisophically, you can't say either way. For example, consider the case where the kernel scheduler uses random numbers from a hardware random number generator which uses quantum uncertainty. Since physics doesn't know whether or not quantum mechanics is deterministic, we can't say whether or not this system is deterministic.


I was assuming a deterministic scheduler, but sure. I wasn't aware that hardware RNG's were commonly used by kernel schedulers.


If the cores aren't at the same speed it can probably happen.


> Since physics doesn't know whether or not quantum mechanics is deterministic

Just because we don't know the laws that govern quantum mechanics doesn't mean they're not there.


Knowing the laws wouldn't necessarily make the system deterministic, though. You'd need hidden variables (and non-local ones, to boot).

As best we can tell, sometimes certain information doesn't exist so you may very well get something truly random that averages out to something that looks like what we think of as deterministic, classical behavior.


I would say there are just so many unknown variables (probably impossible to know), to the extent that people can get away with pretending that it's non-deterministic, when it actually is deterministic.


<former physics minor pedantry>

Which is why there's no way to be certain that it is or is not deterministic. According to current knowledge, quantum uncertainty is not deterministic -- solving the Schroedinger wavefunction for hydrogen, for example, shows no way to predict the future location of an electron. The best we can do is a probability distribution.

If, however, as the parent mentions, hidden variables do exist behind quantum mechanics, it could turn out that it was deterministic all along.

</pedantry>


> "Equation X doesn't help us understand phenomena Y"

How does that even remotely suggest non-determinism?

> If, however, as the parent mentions, hidden variables do exist behind quantum mechanics,

Isn't it obvious that we're not even remotely close to knowing everything?

The uncertainty principles simply suggests that we perhaps can never grasp or understand all the details; it doesn't in any way imply that these unknown details don't exist. It'd be foolish to think that "because we can't predict it therefore it's non-deterministic".


This is a bit of a silly statement, as it's grossly misleading. Firstly, in the very strictest sense it isn't true, given that defects in operating systems and processors and single event upsets due to cosmic rays can introduce some degree of randomness into computer processing. Secondly though, even ignoring all of that, it's not helpful. It's a bit like telling a chemist "remember, the chemicals will always do exactly what you tell them to." Well, sure, that's true in the abstract, but the full complexity of the entire process is greater than any human mind can cope with, so it's necessary to use models and techniques that bring that complexity down to human scale. The same goes for the full breadth of the complexity of programming significant pieces of software today.

The computer will do exactly what you tell it to, but your brain is not capable of determining exactly what the computer will do (it'll process billions of instructions a second, if you tried to fully map out the operations of a computer in complete detail you wouldn't get even a fraction of a second done in your lifetime). Which is why we have to use abstractions, models, and various techniques to render that complexity manageable by human minds.


Down voted for lacking a sense of humour. Seriously, why did you feel the need to explain at large that computers are deterministic when OP was clearly making a joke. (I know I'm probably going to get down voted myself but I had to vent off)


Having read the post you voted down, I don't think he/she was actually responding to my joke but to the concept I was quoting. He/she seems to be arguing against computers being entirely deterministic at all.

I wish there were a better/more formal way to quote things on HN as it can lead to confusion with attribution. Purely italic text doesn't quite cut it, but nor does the "source code" quoting feature.


All the more reason why I hope that history remembers multithreaded programming as an experiment gone horribly wrong.


Computers don't make mistakes, people do.


People make computers.


"There are only two hard problems in Computer Science: cache invalidation and naming things." - Phil Karlton


"There are only two hard problems in Computer Science: cache invalidation, naming things, and off-by-one errors."


Computer Science =

  1. How to represent data

  2. How to transform representations


Or to borrow from CS 101:

  1. Data Structures
  2. Algorithms


  3. ...
  
  4. PROFIT!


1. Nobody really knows how to do it

2. If you think you have a reliable system for doing it, you're probably doing the computer's job


This is fortuitous, because just this week I started realizing there are Two Things about AI:

1. Graph search

2. Representing problems as graph search


For (2) I'd try to work in:

  - multi-agent systems
  - knowledge representation/reasoning
  - machine learning
  - CSPs
"Learning" probably captures the bulk of it.


Knowledge representation--depends on which kind. The kind that involves logic and resolution turns out to be just another problem that you have to represent as graph search.


On the low, algorithmic level that's often true, but a lot of the difficulty imo is at higher levels of the stack. We're very good at writing SAT-solvers, for example, but directly writing problems as SAT is not a particularly good knowledge representation, especially if you want to build systems that are flexible and can interact with humans.

So a lot of the interesting work (imo) is on non-graph knowledge representations, like answer-set programming, situation calculus, etc. They often ground out in some variety of graph search to do the inference, but that's just the solver algorithm, not where the research that interests me is at. It's like saying that graph search grounds out in x86 asm twiddling bits in a computer, so all AI is just bits in a computer, which is also true but misses the point.

Though it does remind me that there was a comment from someone in the 60s or 70s amounting to, "all AI boils down to heuristic search".


> Make it work, then make it elegant, then make it fast.

I usually find that making it fast makes it inelegant.


Making it 'raw fast' is what compilers/JITs are for.

You still need to pick the right algorithms, but I've personally been really focusing on elegancy. Maintenance and Operation of code is the major costs of software, not writing new stuff -- so when you write new stuff, I believe that decreasing those other costs should be the first priority.


I think you mean "elegance". ;-)

That said, I agree with you. Most of the time, the elegant solution is fast or can be made fast.


I agree completely. A common mistake is thinking that performance can be tacked-on later. Thinking about performance up-front can inform elegant designs.

'git' is a good example of this.


Targeted performance improvements tend to make specific operations more efficient. Elegant architectures tend to completely eliminate huge swaths of duplicate and unnecessary operations, and so typically have the opportunity for much greater performance improvements.


I don't find that at all — I find that keeping it elegant keeps it adaptable, applicable in a broad set of circumstances, and understandable. And that these things keep a program from getting slower over time (both pre- and post-deployment) as requirements change.

I also find that a lot of times when programmers look at something elegant and say "that'll be slow", it's because they're wrongly estimating the relative speeds of things. A common example: they're counting function calls when they should be counting I/O operations that are many, many orders of magnitude slower.


I'd add "make it work right" as the second entry :)


Closely related to the first Thing of problem reductionism: "All problems in computer science can be solved by another level of indirection... Except for the problem of too many layers of indirection." — David Wheeler


1: You love it, 2: You hate it.


The two things about software engineering:

1. You have to figure out what you need to build.

2. Engineer the solution in such a way that changes in the requirements result in relatively minor changes to the code.



Every problem can be solved by breaking it up into a series of smaller problems.

A good ballpark, but not entirely true. At some point you'll end up with a smaller problem that cannot be broken up further. For the most part these may be solved problems, like `increment foo`, but at some point you might hit an unsolved atomic level problem that you either need to spend a lot of time working on, or forces you to find an alternative path.


When you hit a problem like that, it's time to start going in the other direction. All problems in computer science can be solved by another level of indirection.


Please solve the halting problem with indirection. Thanks!


Sure! Here's your wrapper that abstracts the concept of processes and never says 'done'.


Some computations (and most computations of practical importance) do halt eventually.


Doesn't matter, it's indirected away. All you know is that you were done asking it for data.


I don't get it.


You have a program. It has input and output, and is either running or done. With abstraction, you can have a view of the program that is just a bidirectional data pipe. You give it information, you request information back. At some point you're done talking to it and drop the reference. The entire idea of 'halting' is gone.


No, that doesn't work, because programs in general don't give one output bit per input bit, and they can also take a very long time to come up with their answer.

E.g. input stream: stream of description of Turing machines and their input tape. Output stream: A stream of booleans that are true iff the respective machine holds.


I guess I should have addressed that idea specifically. If you transfer total control to a subprogram that directly looks for halting, you've just moved the problem, you haven't really abstracted it.

Apply indirection to anything with unspecified runtime. When you need a result, put a reasonable waiting time on it, and if it doesn't happen assume the source has died and handle it as an error code.


1. Solving the right problem

2. Managing Expectations


That's beautiful. However, programming is only one of many fields for which you could apply those "two things".


Interesting. So perhaps we're talking about the 'two things' that are specific to software development. Maybe it's worth considering the rest of the different 'two things' that apply more generally as well?


I think this applies to all client-based work, programming included.


1. You're assuming things that you've not verified.

2. You've overlooked or ignored things that need to be considered.

Pretty much sums up the source of all pain in day-to-day programming.


1 and 0


You left out the set-up line: "Fundamentally, there are 10 things about software:"


I'd change second thing about Computer Programming to: "Something ALWAYS goes wrong and your job is to fix it"


The two things in computer programming are automation and abstraction. That is all.


The two things economists know are hilarious -- square "no free lunch" with "gains from trade." Do the gains from trade have a price? Who pays that?

As for "incentives matter," what, because incentives incentivize?


I feel like the two things economists need to know are:

1. You don't know what you're talking about.

2. You don't know it yet.


1. Defining problem space.

2. Input/Output.


And some computation.


I knew my #2 would be taken more literally than I meant it. At a very fundamental level, computation consists of moving bits, hence I/O.


This reminds me of: "All Our Programming Languages Boil Down to Sequence, Selection and Iteration"

http://bit.ly/9lwT8e


hmm, i was thinking 'All problems can be solved by another level of indirection' should be somewhere pretty high up...


1. Nearly every decision makes the simple stuff more complicated

2. Accepting thing #1 will make you a better programmer


Interesting idea - but I have never worked out what the two ideas of biology are.


Simplicity and beauty are my two coding principles.


1. Write for the computer

2. Write for the human


1. Abstract thinking

2. Empathy for users and other programmers




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: