Hey gang -

I'm working on a manuscript that covers Patterns and OOP in Perl, and have gotten to a point where I could use some feedback. With your indulgence, I'd like to post chunks of the work every now and then so other people can sniff-test and sanity check it.

Please note that I am not trolling for someone else to do my homework. I know exactly where I want to go, I'd just like to make sure that I'm expressing myself clearly. If you're worried that I might plagiarize your suggestions, please don't post.

The opening of the first chapter is below the fold.

--- Introduction This chapter walks through some basic programming theory. Patterns are collections of objects, so to understand patterns, you need to understand Object-Oriented Programming (OOP). Objects are Turing machines, so to understand OOP, you need to understand Turing machines. Programming theory is the study of Turing machines, so if you really want to understand Patterns and OOP, it helps to know the underlying theory. ---- So what are Turing machines? The Turing machine is the conceptual foundation of programming theory. It's the simplest device that can do anything a computer can do. Mathematically, a Turing machine is an ordered 9-tuple: M = (Q, Ai, At, _, |, d(), s, a, r) where: Q is a set of states Ai is the input alphabet At is the tape alphabet _ is the blank symbol | is the left end-marker d() is a transition function s is the start state t is the accept state r is the reject state and you don't have to memorize that, we're just laying it out for future reference. Conceptually, a Turing machine has three parts: - a tape that consists of discrete 'cells' - a decision engine called the 'finite control' - and a read/write head that connects them --------------------- | | | | | <-- Tape --------------------- ^ | <------------- Read/write head +---+ | | <------------- Finite control +---+ A Turing machine starts with its read/write head at the tape's left end. To program a Turing machine, you fill its tape with symbols from the input alphabet, put the finite control in the 'start' state, and set the machine to work. For each cycle of operation, a Turing machine does four things: 1. it reads the symbol from the cell currently under the head 2. it puts the finite control in a new state 3. it writes a new symbol back to the current cell 4. it moves the head to a new position on the tape Then it goes back to step 1 and repeats the cycle on the new cell. The cycle continues until the finite control reaches either the 'accept' state or the 'reject' state. When (or rather, if) that happens, we say the machine 'halts'. The contents of the tape when the machine halts are considered the program's output. Now, that doesn't look much like regular programming, let alone OOP. Appearances can be deceptive, though. The Turing machine is computationally equivalent to another machine, called the Random Access Machine, that looks more familiar. ---- The Random Access Machine The random access machine is the generic abstraction of a digital computer. It has a central processing unit with a set of built-in instructions, a bank of addressed memory, and a bus that carries data between memory and the CPU: +-----+ +-----+ | CPU |--- memory bus --+-->| | +-----+ | +-----+ +-->| | | +-----+ +-->| | | +-----+ ... | ... | The CPU also contains two special memory locations called 'registers': - an accumulator - a program counter that perform special functions while the machine works its way through a program. Each of the CPU's built-in instructions has a corresponding symbol, called an 'opcode' that can be stored in memory. To program a random access machine, you load a series of opcodes into memory, load the address of the first symbol into the program counter, and set the machine to work. For each cycle of operation, the random access machine: - reads the program counter, - fetches the appropriate opcode from memory, - executes the corresponding instruction, - and advances the program counter which is similar to the operating cycle of a Turing machine. In fact, it's tempting to say that the random access machine is exactly the same as a Turing machine. The program counter and bank of addressed memory do the same thing as a tape with a read/write head, and the symbols that represent instructions look much like a Turing machine's tape alphabet. Unfortunately, it's not quite that simple. A random access machine's instruction set can do things that a Turing machine's tape alphabet can't. A random access machine could have an instruction that adds two numbers together, for instance. A Turing machine can certainly add numbers, but you can't reduce addition to a simple table that maps symbols A and B onto symbol C. Or rather, you can, but you'll need an infinite number of symbols, and a Turing machine uses a finite tape alphabet. That doesn't make a random access machine more powerful than a Turing machine, though. It just means that a random access machine can do more work per cycle of operation than a Turing machine can. To show how the random access machine is equivalent to a Turing machine, we have to dig a little deeper. Generally speaking, a random access machine does one of four things in each cycle of operation: - it loads the contents of a memory location into the accumulator, - it manipulates the contents of the accumulator, - it stores the contents of the accumulator to memory, - or it sets the program counter explicitly. And while a Turing machine can't do some of those things in a single step, it can do them all in multiple steps. In fact, you can say that a random access machine is made of one Turing machine nested within another. The outer machine uses the bank of addressed memory as its tape, and the inner one uses the accumulator. The outer machine carries information between the accumulator and memory, and the inner one manipulates values once they reach the accumulator. Now you'll have to take this on faith for the moment, but we can make a single Turing machine do anything a collection of Turing machines can do. The single machine will be bigger, slower, and more complicated, but it will still do everything the collection can do. That means we can program a Turing machine to simulate a random access machine. We can write programs to simulate an accumulator and program counter, addressed memory and a set of built-in instructions with opcodes. Therefore a Turing machine can do anything a random access machine can do. The opposite is also true. A random access machine can be programmed to act like a Turing machine. Either machine can do anything the other one can, so the two machines are said to be 'computationally equivalent'. ---- Objects Objects are random access machines. If you look back at the description of random access machines, you'll notice that I carefully avoided saying that the memory is addressed numerically, or that the memory locations store fixed-width binary integers. Those are details that constrain the theory to a specific implementation, not part of the theory itself. A numeric memory address is just a label, an opcode is just a symbol, and a bank of 8-bit bytes is equivalent to a tape with an alphabet of 256 arbitrary symbols. An object's attributes are discrete chunks of addressed memory. Its methods serve as a built-in instruction set. Attributes have human-readable names rather than numerical addresses, and can hold arbitrary values. Methods can perform arbitrarily complex operations, instead of being limited to primitive binary logic and branching. As far as programming theory is concerned, though, none of those distinctions make any difference. It would be trivial to create an object that simulates a random access machine. The accumulator, program counter and memory bank would be attributes. The instruction set would be a collection of methods, and each method would map to a symbol that could be stored in the memory array. By the same token, a random access machine can be programmed to act like an object. With suitable programming, it could translate a set of human-readable names into ranges of memory that represent values of arbitrary type. Then it could simulate methods to set and manipulate those values, or to do anything else that an object method can do. And since a Turing machine can do anything a random access machine can do, an object is just another kind of Turing machine. The key to understanding OOP is to realize that each object is a *distinct* Turing machine. Each object has its own private set of attributes, which makes it equivalent to a random access machine with it own private address space, or to a Turing machine with its own private tape. By those terms, the central concept of OOP can be summed up in just three words: no shared tape An Object-Oriented program is a network of objects that, ideally, share no data storage at all. Classes, inheritance, access control, and all those other OO terms are derivative concepts that we'll deal with later. Either they involve communication between objects, or they involve telling a runtime environment how to create new objects. Before we can make sense out of those, you need to understand how objects themselves work. ---- Programming theory Programming theory is pretty much the science of understanding Turing machines.. what they are, and how they work. And as with most sciences, programming theory breaks Turing machines down into pieces that are smaller, simpler, and easier to understand. The simple machines of programming are: - Simple expressions - Parametric expressions - Finite automata - Pushdown automata - Turing machines Each one corresponds to a certain kind of information: - Simple expressions == values - Parametric expressions == enumerable sets - Finite automata == regular expressions - Pushdown automata == context-free grammars - Turing machines == contextual recursive grammars And each one lets programmers work with certain basic concepts: - Simple expressions == representation and identification - Parametric expressions == relation - Finite automata == state and behavior - Pushdown automata == encapsulation - Turing machines == arbitrary data storage The next few sections will examine those machines, types of information, and concepts.

Replies are listed 'Best First'.
Re: RFC - OOP and Turing machines
by gmax (Abbot) on Jan 03, 2002 at 14:38 UTC
    I won't say that your node is off-topic, since you promised to show us something in Perl. ;)
    In the meantime, I would like to share some comments about your first chapter, and you are free to plagiarize me :-).
    I will start by saying that you are expressing your ideas very clearly. So clearly, though, that there are a couple of points that appear to be too strong in comparison to my previous education.
    Personally, I love this subject, and I have read a lot about programming and computer theory. I know how Turing machines are related to computer programming, but this is the first time that I see them identified with programming theory.
    IMHO, programming theory is more than just studying Turing machines. It is true that you can program a Turing machine to do any task but I don't see why we should pass throug them to explain everything else. Don't get me wrong. I just think that the relationship you are stating is too strict and committing.
    It is your opinion that programnming theory is identified with the study of Turing machines. Another opinion could be that you can explain programming theory without ever mentioning Turnig machines. Yours could be a well supported opinion (if you can substantiate it with good references) but it is not the only view in programming theory.
    Also stating that objects are Turing machines looks to me like you are stretching the issue a tad too much. I can see your point and I understand it, but it seems to be too extremistic, and as an average reader, I am not ready to accept it unless you can back it up with some hard evidence.
    The same remarks I would make for patterns. You say "so to understand patterns, you need to understand Object-Oriented Programming"
    I should say that OOP is one view of the issue, but not the only one. Patterns can be explained in terms of structured programming, and actually I learned about patterns long before the term OOP hit the bookstores. I don't object to the technology (I was one of the first teachers of OOP in Italy in the early nineties) but just to this strong relationship. OOP can explain patterns, maybe better than structured programming, but it is not the only game in town.
    Apart from that, You are doing fine, your prose makes a pleasant reading and I am curious to see the Perlish part of it.
    _ _ _ _ (_|| | |(_|>< _|

      Thank you.. that's exactly the kind of feedback I'd hoped for.


      > I will start by saying that you are expressing your ideas very clearly.
      > So clearly, though, that there are a couple of points that appear to be
      > too strong in comparison to my previous education.

      Point taken.. thank you. You're right that there are many ways to view the subject, and I don't want to sound like an advocate of The One True Way. I oversimplified through a combination of keeping things terse and being alone with my notes for too long.


      > ... and I am curious to see the Perlish part of it.

      Hmm.. another good point. The first couple chapters are heavy on theory, and the rest refer back to them while explaining the code for specific patterns. You're right that people will want to see some code, though. I'll have to crank out some sample code so people can see the ideas in action, rather than just relying on diagrams.

(ichimunki) Re: RFC - OOP and Turing machines
by ichimunki (Priest) on Jan 03, 2002 at 21:46 UTC
    Although I think Perl might not be the most ideal language for discussing OOP, I would be *very* interested in seeing the ideas in this chapter expressed as Perl scripts (preferably objects). That way some of your assertions can be demonstrated so that those of us who struggle with the abstract concepts here can see a concrete example, rather than trying to form our mental image only from words and diagrams.

    To that end, you should build as concise a Machine::Turing class as you can, maybe with some very simple methods:
    • initialize: accepts a reference to a list to be used as a tape
    • cycle: performs one cycle in the machine
    • state: so that we can find the tape position, and maybe the result of the last write
    With just these three methods I think you would clearly capture everything we want to be able to do with a Turing machine, and you'd have an opportunity to introduce some idiomatic OOP scripting right away. Also, then when you state that we can do anything with multiple Turing machines that we can do with one, you might be able to demonstrate that. You would also be able to show how the Machine::RandomAccess class would look in comparison.

    And in this way your conclusion, that all objects are simply Turing or random access machines, is even easier to bear out-- as you can then point to the characteristics that all objects have in common with your example implementations of these two machines (and therefore with the abstract ideas that those Machine::* classes represent).


      > To that end, you should build as concise a Machine::Turing class as you can ...

      Hrm.. interesting suggestion. The code itself would be easy. I'll hammer out something and post it in the next day or two.

      I don't want to hit people with raw TM code right off the bat, because it tends to look like line noise. The logic of the program is distributed across the whole machine, and the connections aren't obvious until you know where to look. The whole point of the chapter is to teach people where to look, though, so I can introduce the class's interface one piece at a time as we walk through the heirarchy of simple machines.

      I think I'm going to upgrade that to "a most interesting and excellent suggestion." Thank you very much.

      Hi,
      did someone implemented the idea of ichimunki? It looks interesting... If no one already did it, I'll be interested in trying.

      Cheers
      Leo TheHobbit
      GED/CS d? s-:++ a+ C++ UL+++ P+++>+++++ E+ W++ N+ o K? !w O? M V PS+++
      PE-- Y+ PPG+ t++ 5? X-- R+ tv+ b+++ DI? D G++ e*(++++) h r++ y+++(*)
Re: RFC - OOP and Turing machines
by hsmyers (Canon) on Jan 04, 2002 at 01:47 UTC
    Patterns are collections of objects, so to understand patterns, you need to understand Object-Oriented Programming (OOP).

    That's odd, my copy of A Pattern Language by Christopher Alexander and Sara Ishikawa and Murray Silverstein. New York, NY., Oxford University Press, 1977., doesn't say anything about Object-Oriented Programming! You might want to either show us the missing portion of your work or qualify such statements, since they don't stand too well on their own.

    –hsm

    "Never try to teach a pig to sing…it wastes your time and it annoys the pig."

      Got it on my bookshelf, along with a couple others from the same series. It's an excellent book, very readable, and IMO absolutely indispensable for anyone who wants to make a career in architecture or civil planning. I don't know how much I agree with Alexander's opinion that ultralightweight concrete is the future of residential construction, but I do like his writing style.

      You can also find books on business and management (Anti-Patterns (Brown et al., John Wiley & Sons) springs to mind) that use the term 'pattern' to discuss business processes and human interaction. Nor should we forget the fields of knitting and metal casting. I don't know of any significant body of work within the literature of computer programming that uses 'pattern' exclusively of OOP, though.

      Design Patterns (Gamma et al.) and various papers in PLoPD 1-4 (Addison-Wesley, various authors, various editors) cite APL as a source of inspiration, but then use 'pattern' to refer to collections of objects without additional qualification. UML and its associated literature don't even mention APL as far as I know, but UML clearly contains notation for patterns. I intend to cite APL in my chapter on patterns (the above is from the chapter on OOP), so I should end up being consistent with established usage.