Software Development optimize

Multithreading is a verb not a noun


Steve Yegge's rather famous post, "Execution in the Kingdom of Nouns" has probably done more to frame and influence my thoughts about object-oriented programming (OOP) than anything else out there. In the discussion thread about my post on multithreading loops, I finally got a handle on why I feel that multithreaded work is significantly more difficult than it needs to be: the noun-oriented nature of the languages that I have written multithreaded code in. Of course, it is entirely possible for there to be an OO language without the focus on nouns (Chad Perrin says that Ruby is one of them, but I have not worked in it). But, at the end of the day, the noun-ness of mainstream OO languages makes multithreading no better than miserable to work in.

A great example of what I am talking about is the code in my VB.Net multithreading series. Look at the code for working with a monitor. This simple example is fairly hard to follow to be honest. By glancing at the code, even someone who knows VB.Net and multithreading fairly well like myself cannot quickly judge what is going on.

Why is this? Because multithreading is an extreme example of what Steve Yegge's article is about. Multithreading is purely verb oriented, and the objects involved do not need to be. The programmer does not need to be passing about a mutex object, for example. Mutex's are active across the entire system, so why even bother to pass them around? Why not have a "lock" command and pass it parameters like scope (which would determine whether it used a mutex or a monitor) and the name of the lock, and have the run time environment manage a hashtable of various locking objects? Let's ditch these semaphore objects and have the language have a "listen for signal" command and a "send a signal" command. Would this be too difficult?

I truly doubt it! The fork() command on UNIX has been around forever. Regardless of your language, using a process fork on the UNIX platform feels the same because it is a base feature of the OS, and various C-style languages all expose that functionality fairly identically if they expose it. Furthermore, System V IPC is already a standardized, verb-based system.

There is already one example of this: SyncLock (that's VB.Net parlance, it is simply "lock" in C#). SyncLock does a cheap monitor lock against an object that you provide. Sadly, extending VB.Net or C# at the level of creating a new block construct is either very tough or impossible to the best of my knowledge. If it was possible, it would be fairly easy to write a DSL (like LINQ is) to perform multithreading, and then use that DSL within VB.Net, C#, etc. to easily handle the multithreading work without having to explicitly and overtly deal with the .Net Framework's ugly, noun-oriented multithreading systems. Indeed, SyncLock "feels" really out of place; I cannot think of any other language-level statements in VB.Net that accept any type as a parameter and actually work -- even the built-in casting calls like CInt and CStr are limited to certain types; calling CInt on a Bitmap object is a compiler error, not a runtime error.

The problem is that the "Kingdom of Nouns" values conformity over utility. There are some very good reasons for it. If I can demand an exception for multithreading work, then someone else (just kidding, it would be me again) would demand that regex's be run as an operator the way that Perl does. And then someone else would want their domain-specific functionality to be bumped up to function or operator status. And the next thing you know, we turned C#, Java, or VB.Net into K&R C with a huge set of libraries pre-included. Yuck.

I think maybe what would be better (and this is why I love the .Net CLR) would be to have something similar to LINQ but for multithreading, and write it in a language much better suited for this work. Then, access this DSL in the same consistent way regardless of what language your project is actually in, much as everyone uses the Perl regex syntax now. LINQ is based on closures; doing something similar could very well be the ticket to making the .Net ecosphere a multithreading paradise. (MSDN has a great in-depth article on how LINQ works.)

Interestingly enough, it looks like Microsoft Research is already headed down this path. Let's do the math here. F# gets more and more mentions from internal Microsoft people. Closures are getting added to VB 9 (in .Net 3.5) because LINQ requires them. LINQ and a rather SQL-like (and therefore, imperative feeling) structure gets added across the .Net board, replacing and improving on a wide scale the concept of "query," and with it, much of the existing ADO.Net structure. Microsoft has been throwing a good deal of effort behind IronRuby and IronPython. Team Foundation Server, plus the associated tools, can do much of the organizational stuff that OO helps with, in terms of multiple programmers working on the same codebase. Microsoft Research is adding "design by contract" to C# with Spec#, a superset of C#. Add this all up, and it says to me that Microsoft is starting to push very hard against strict OO. Hopefully, Microsoft Research's TPL will do for multithreading what LINQ is doing to the concept of queries.

J.Ja

About

Justin James is the Lead Architect for Conigent.

38 comments
alaniane
alaniane

Looking at this article and the comments, I think I now know why I prefer a language like C++. It's because it is neither completely OO nor procedural-only. IMO it is better not to place all of my eggs in one basket. Object-oriented code has its place; however, sometimes non-OO code is preferable.

RetiredCPA
RetiredCPA

Multithreading is actually a gerund, that is the nomnative form of a verb.

jean-simon.s.larochelle
jean-simon.s.larochelle

The libraries now include most of the classes and tools described in Doug Lea "Concurrent Programming in Java(TM): Design Principles and Pattern (2nd Edition)". You still have to be extra rigorous with MT programming but it is required for some application and therefore you can't avoid it. It also helps if the tools available for your language include a good static analyzer. In the case of Java FindBugs is really good and will help trap inconsistent use of locking and other such problems (this is still evolving as we speak). Annotations (net.jcip.annotations) from Brian Goetz "Java Concurrency in practice" are a nice addition to this and will get more useful as the detectors in FindBugs are completed and improved. JS

Mark Miller
Mark Miller

Hi Justin. You're on the right path. Here's a quote from Alan Kay from 10 years ago. You probably read it on my blog, but it dovetails with what you're talking about here: "A lot of, I think, our confusion with objects is the problem that in our Western culture, we have a language that has very hard nouns and verbs in it. So our process words stink. So it's much easier for us when we think of an object--I have apologized profusely over the last 20 years for making up the term 'object-oriented', because as soon as it started to be misapplied, I realized that I should've used a much more process-oriented term for it." If Kay could've gone back in a time machine he would've expressed the concepts he was talking about differently. Instead of coining the term "object-oriented programming", he would've preferred that he used the term "message-oriented programming" (MOP). The understanding that's evoked by this term is that computation is done via. message passing. Typically messages are verbs. What this means is that the objects are not nearly as important as the messages that are passed between them. Kay has said many times that the true abstraction in OOP is in the messages passed to/between objects, not the objects themselves. That is true OOP, not the noun-based misunderstanding of OOP that has been implemented since it was invented. Smalltalk is message-oriented, even though it's often called "the first OOP language". I tried out some threading in Smalltalk a while ago. I was doing some experimenting, trying to create my own screen capturing in Squeak. The following code coordinates actions between two threads without me having to use semaphores: frameLimit := 25. "SharedQueue is a generic thread-safe container" sQueue := SharedQueue new: frameLimit. continue := true. frameDelay := 100. "This thread captures the screen frames" [ [continue] whileTrue: [time := DateAndTime millisecondClockValue. "Captures screen and puts it in the shared queue" sQueue nextPut: (Form fromDisplay: (0@0 extent: DisplayScreen boundingBox corner)). frameTime := DateAndTime millisecondClockValue - time. (frameTime < frameDelay) ifTrue: [(Delay forMilliseconds: frameDelay - frameTime) wait]] ] fork. "This thread saves the frames that have been captured" [ fileNumber := 1. [continue] whileTrue: ["get frames from shared queue" receivedFrame := sQueue next. receivedFrame writeOnFileNamed: 'frames\', (fileNumber asString). fileNumber := fileNumber + 1. receivedFrame := nil] ] forkAt: Processor lowIOPriority. Here's a Ruby threading example from the Pragmatic Programmer's Guide to Ruby. You can see the section on Ruby threading at http://www.rubycentral.com/pickaxe/tut_threads.html. It grabs web pages with a separate thread for each page: require 'net/http' pages = %w( www.rubycentral.com www.awl.com www.pragmaticprogrammer.com ) threads = [] for page in pages threads

Justin James
Justin James

If you do MT work, does the way your language handles it help or hinder your work? If you have not tried MT yet, is it because the constructs make no sense? J.Ja

apotheon
apotheon

Y'know, "multithreading" could (depending on context) be a participle instead of a gerund. For purposes of the point of Justin's article, I think "verb" is close enough.

Justin James
Justin James

"I am working on some multithreading" would be a gerund. "I am multithreading this code" would be a verb. That being said, I was talking more at the conceptual level of the code process. If you look at what multithreaded code accomplishes, it is all actions operating on nouns: * Forking a process * Signalling a thread * Incrementing a semaphore * Entering a monitor etc. When you wrap something that is so action oriented in an OO cloak, you get a mess like: System.Threading.Monitor.Enter(oLockObject) Which is really backwards at a mental level... you want to *enter a monitor*, not *have a monitor perform an enter function on an object*. J.Ja

Justin James
Justin James

I know that Java is improving its threading support, but do you find that the noun-oriented syntax of Java hinders the way you think about the coding, maintenance, and debugging? J.Ja

Justin James
Justin James

Ruby's use of a closure (and Smalltalk's) is actually not too different (in some sense) from .Net's, where you pass it the address of a delegate to me called when a thread is executed. While the address of a delegate is, of course, not nearly in the same ballpark as a closure, the principle is the same in that the thread wraps around an already established chunk of code. J.Ja

apotheon
apotheon

That's the quote I was thinking of, in [url=http://techrepublic.com.com/5208-6230-0.html?forumID=102&threadID=238568&messageID=2330523][b]this post[/b][/url] of mine (in the same subthread to which Justin linked, when he referenced my comments about Ruby). The key point is this one: [i]I have apologized profusely over the last 20 years for making up the term 'object-oriented', because as soon as it started to be misapplied, I realized that I should've used a much more process-oriented term for it.[/i] Alan Kay's a smart guy.

apotheon
apotheon

I'm writing more Ruby than anything else these days (other than English). Unfortunately, it doesn't quite measure up to my standards for multithreading concurrency support, because it only provides "green" threads (aka "fake" threads). The rumor is that this will change with Ruby 2.0, and I'm waiting to see how that works out. Of course, there's a school of thought to the effect that multithreaded concurrency support is a misfeature -- that concurrency should be multiprocess, not multithread. It is generally considered a fact of life that threads generate less overhead than a whole new process, and it may be that in certain types of projects it's more convenient to have all your concurrency management happening in the same code, but the former justification could be regarded as a case of premature optimization and the latter as a poor trade-off in programmer productivity -- swapping out a little process handling complexity for a lot of thread handling complexity. As far as I'm concerned, the jury's still out -- though I'm somewhat inclined to lend the multiprocess argument some credence, because of my beliefs on the subject of modularity (that all else being equal modular code is preferable to monolithic code, modular programs are preferable to modular code, and many utility programs working together are preferable to modular programs). I know that the multiprocess argument and the modularity argument aren't exactly equivalent, however, and am keeping an open mind as I find myself looking more and more toward concurrency for my future development efforts.

Mark Miller
Mark Miller

What you're really after here is acquiring exclusive access to the object. I imagine what you mean by "enter a monitor" is akin to entering a critical section. There is a "lock" keyword in C#. You can read about it at: http://msdn2.microsoft.com/en-us/library/c5kehkcz(VS.71).aspx It enables you to say: lock(this) { // code ... } It creates a critical section that gives exclusive access to that section, and then when scope leaves it the lock is released. You could conceivably use this in your projects, even if you're using VB.Net. You can write your thread-safe code in C#, in a separate DLL. Not that convenient, I know, but it might get you a bit closer to what you want for now. If you want something that's more semantically relavent in VB.Net: AcquireExclusiveAccess() System.Threading.Monitor.Enter(Me) and, ReleaseExclusiveAccess() System.Threading.Monitor.Exit(Me) That way you could at least do: oLockObject.AcquireExclusiveAccess() Monitor and semaphore classes exist in Smalltalk as well. In that realm, the recommended method for passing control of an object to a thread is through a SharedQueue object, instead of using monitors and mutexes with it. These are used inside of SharedQueue, hidden from the threads. You can look at my Smalltalk threading example to see some of how it's used. SharedQueue is thread-safe and can handle a many-to-many relationship. Many threads can put stuff into it, and many threads can take things out of it. You can have as many queues as you want. You can think of it as an asynchronous form of message passing. You can also use it in a blocking or non-blocking way. One message blocks on the queue. It forces the thread that uses it to wait until an object is available. Another one is non-blocking, just returning nil if nothing's in the queue. If you have an object you're passing around from thread to thread frequently, what you could do is put the object into a queue, start up your threads that need it, and have them try to grab it out. Whoever does gets sole posession of it. When they're done they can just put the object back into a queue for other threads to grab. This way the queue provides the exclusion, not monitors and semaphores. Perhaps this would be a better threading architecture for you? I looked around for a thread queing architecture in the .Net framework and there is a Queue container in .Net Framework 3.0. I looked at the documentation for it, but it doesn't say if it's thread-safe or not. If not, given what you have, it would be possible to implement a SharedQueue yourself.

jslarochelle
jslarochelle

... I enjoy the noun "orientedness" in Java. I tend to think of threads more like electrical power on an electronic board where objects are the different components (ICs, capacitors, resistors, ...). I try as much as possible to do things with one thread. However like I mentioned previously for some of my work I need multiple threads because I don`t want my main thread to wait afer a slow external device. Of course in the past multiple threads were not very usefull unless you could find a task in your applications that could run at a lower priority than your main task. Now with the availability of "real" parallel processing the domain of useful applications will get larger. Because we do a lot of numerical processing and some of it pretty CPU ungry I welcome this. A clear application for us will be for Neural Nets or Genetic Programming. We are looking at both of those for future version of our software. Now comming back to the syntax maybe I have grown so use to it that I don't see the problems anymore. However, I would enjoy a few enhancement. For example a Delphi like "with" keyword would be welcome. I would also welcome new keyword that would let me use the fancy ReadWrite locks from the java.util.concurrent library without the extra code (catch/final block to release the lock). But none of this has anything to do with the fundamental noun orientation of the language. For us working on a fairly large project OOP has been a benediction. Although it took some time for this to take shape. In fact I think that Java (because of its simplicity and large libraries) and OOP have been an essential part of the success of the project. I think that once you see the benefit of OOP you forget the inconveniences of the syntax on a long term project such as the FTSW100. I have been working for 9 years on this project and the product still as a long life in front of it. Future version of the product even major rewrite will be able to reuse much of the code in the current version because this code is nice and lean and has a whole bunch of Junit tests that comes with it. The code can be modified and regression tests can be done on it very efficiently. Even things like assigning processing of different parts of a large matrix to different CPU could be tested and validated. So, my opinion about this whole business of syntax and noun versus verb orientedness is I guess a special case. JS

apotheon
apotheon

I rather suspect that, as concurrency becomes ever-more important to programming practice in the near future, use of closures will become more common and more important. The slavish devotion to "standard" objects in most mainstream application development these days will have to give way to such high-order function techniques as closures because of the protection, encapsulation, and "mobility" characteristics of such program constructs. Those sorts of characteristics will become more critical to good software design as concurrency becomes more important, as a means of passing both data and process around without having to duplicate effort and without increasing risks of tight coupling. Thank goodness, I say. As closures become more critical to concurrency, their value will be more widely recognized -- and they'll filter down into uses where they aren't quite as critical, but can still greatly improve the practice of coding, where they've been largely ignored for decades.

Mark Miller
Mark Miller

[i]Alan Kay's a smart guy[/i] Yep. From listening to his speeches I can see why he is misunderstood. Maybe it's just me, but he talks at more of a conceptual level, less concrete, and he tends to assume that people understand what he's talking about, because he does. I think this confuses many technologists, because they're used to people discussing technology either as it is, or "the next step". His vision is years ahead of most people. He was talking about the semantic web 10 years ago when people were still worried about just getting an HTML page up, and maybe making it do something useful. I've found that the more I read and discuss about this stuff the more I understand what he's saying. I've had the experience of watching speeches of his I watched a year ago and finding new meaning in things he said that just went over my head before without me even realizing it. It's because he doesn't elaborate. He just says it, and then he's on to the next concept. I have had the opportunity to talk with Kay a bit by e-mail, and I got confused by something simple he said. He was talking about how OOP expressions are evaluated, and "selectors". He said that selectors are indices into object methods, and said something like "in the expression 3 + 4, '+ 4' causes a selection, which produces the result '7', like 5 selects the 5th element from an array in 'a[5]'." (assuming 1-based indexing) This really got me mixed up, primarily because I've been exposed to C++ and the like. I think "[]" is an operator. Trying to equate the semantics between the two I thought he was giving some set theory explanation for why 3 + 4 = 7 (it selects the 4th element in 3's possible result set like a[5] selects the 5th element from "a"), and I thought he mispoke about the analogy with "a[5]". After some back and forth I realized he was saying, "'+' is an index that selects the 'add' action from '3' (which BTW produces the result '7') like 5 selects the 5th element from a[5]." After I understood it I wondered why I misunderstood him in the first place. :P This brings to mind a quote of his: "There is no idea so simple and powerful that you can't get zillions of people to misunderstand it." I may have stumbled upon the answer for why Kay first coined the term "OOP". An idea came to me while I was discussing Squeak on a forum. I've read a little bit of what he's written about this. He said his first memory of it is when someone asked him in the late 60s what he was working on, and he said something like "it's object-oriented programming", or "an object-oriented system". I've talked with others about analogies to things that are familiar, in operating system terms, to properties of Squeak/Smalltalk. One that Kay made obliquely is in Unix "it's a little hard to have a process that can just be the value 3". In my own mind Unix could be described as a "process-oriented system". So Smalltalk could be described as an "object-oriented system". Or maybe he was comparing it to the mainframes of the time, which were also process-oriented, but in a different way. So the conclusion I came to is when Kay was talking about "object-oriented", he was using an adjective to contrast his system with how other systems were architected. He was not trying to say programming "is all about the objects". He was not talking about the architecture of programming, but of a system. Then the question becomes, "How do things interact in such a system?" The answer is messages.

Justin James
Justin James

Processes and threads have different purposes entirely. I'm all for modularity of code/programs, but at the end of the day, processes are much less helpful for parallel processing. Image processing is a great example. Logically, it is almost trival to split an image into a seperate chunk for each core and run the same code on each chunk, then rejoin the chunks into a whole image at the end. It often (depending upon the language) adds under 20 lines of code, almost zero overhead, little need for concurrency worries, and divides your time to execute by the number of cores that are used (assuming you can grab 100% of CPU per core). That's a darned good deal. Can you do it with processes? Sure you can. But you really do not need the overhead of it. And in many cases, a simple fork() and join() is not too much less work than Thread.Execute() and a semaphore to notify when each thread is complete. I may also add, it seems like processes and threads are getting more closely related, at least in terms of how you deal with them at the code level. J.Ja

jslarochelle
jslarochelle

The annotations are used more for validations right now. They will not generate out code for you. But you could have a tool (an Ant task that runs after the compiler) that would do this for you using reflection and the annotations. Alternatively, you could use AOP (AspectJ for example) to do something like what you describe. You could define an Aspect to insure that calls to a class are all properly sunchronized. This could get quite flexible if you use the existing jcip annotations for this. JS

jslarochelle
jslarochelle

Right now the jcip annotations are not supported specifically by the compiler. However, the open source static analyzer FindBugs has limited support for the jcip annotation and the detectors will get better in future versions of the tools (it is not doing much with them right now). Note that Findbugs will give you warnings about inconsistent locking policy (members being accessed by synchronized and unsynchronized methods) even without the jcip annotation. The jcip annotations will add another level of intelligence to this and will help eliminate false positive and help catch more errors. Another point is that even without Findbugs nothing prevents you from having your own detectors in the form of unit tests that use reflection and the byte code libraries to validate code using annotations. Of course you can also do this for things other than MT. I have written annotations to validate very business specific design aspects of some classes in JUnit tests. That is, you can enforce design decision. It is a lot of work but for critical classes it is a blessing. Really cool! JS

Mark Miller
Mark Miller

That's really what I was after. I wasn't just saying that one could document how a class behaves, but also change its behavior based on these annotations. What I was saying was it would be nice if one could declare a class "shared" and then when threads wanted to call its methods it would handle issues of exclusivity inherently without the programmer having to deal with semaphores and monitors, inside or outside the class. I can understand what you're saying about configuring each individual member variable, because you could end up in a deadlock situation if logic and variables are not handled right.

Justin James
Justin James

Thanks for introducing me to that concept in Java! That is exactly what I had in mind. It makes sense that it is only really visible at the reflection and/or compiler level, but it is still extremely helpful, it means that the code environment can throw out warning when you are using non-thread-safe items in a way that you will need to do your own locking. J.Ja

jslarochelle
jslarochelle

In Java you can use the jcip annotations to flag a class as thread safe or NOT. Then you can annotate individual members of the class to specify how synchronization is handled for each one. If later another programmer comes in and modifies the class without proper annotation and proper handling of synchronization the error can be spotted much more easily (with unit tests or static analyzer). I think annotations are one of the best addition to Java and I would certainly welcome such mechanism in other languages that I use. However, annotations work hand in hand with the reflection API and I don't see how it could be implemented with langauges that don't support reflection. It certainly would not be as usefull JS

Justin James
Justin James

I would also like it if there was a flag or assertations that could be put into the code (similar to the contract assertations in Spec# and Cobra) that declares "I verify that I am thread safe". That would go a long, long way to improving things. Right now, at best, thread safety is a blurb in the documentation, and who knows what the author considers "thread safe"? So instead of being a boolean, multi levels could be provided, such as "I do not use any shared data" or "I enter a monitor to perform this work". J.Ja

Mark Miller
Mark Miller

...I think is if objects intrinsically knew how to handle locks, so that programmers would have to worry less about it. I was thinking as I looked at your example, that if you just use Monitor.Enter(), or even lock()/SyncLock(), that you could potentially have a situation where some other programmer on your team forgets to use Monitor with a shared object, and accesses it just like any other. According to what I read in the Framework someone could do that very easily. It's a "gentleman's agreement" to use Monitor on an object. It seems to me that the runtime doesn't keep track of locks except through Monitor and semaphore objects. I think what would be ideal is if you could define classes and methods with annotations saying "this is shared", and implicit in the method dispatch is the notion that multiple threads are going to try to access it. That way the programmer can just go about the business of writing it without worrying about contention issues.

Justin James
Justin James

Mark - C#'s "lock" statement is actually the exact same thing as VB.Net's "SyncLock" statement. Both of them are merely shortcuts to Monitor.Enter (well, maybe slightly more than that, but Monitor is the foundation of them). They are much closer to what I would prefer than Monitor.Enter, because they describe the action much better. My real issue with them is that they still do not function as part of a cohesive whole. You pass them a random object so they can pass that to Monitor.Enter. What I really would like is not just a syntax change, but an overall awareness of threading and concurrency from within the code and framework. For example, instead of having just SyncLock (or "lock" in C#), why not have a single lock command that just takes a name of the lock, a scope, and an object or block of code (via a delegate or a closure) to be locked? Much easier than having people try to remember the subtle differences between mutex and monitor, and things like that! J.Ja

jslarochelle
jslarochelle

Although I understand much better what you mean by "verb-oriented" I have to say that I don't think that Ruby is that different from Java at the language level. Closures are a clear advantage as far as "verb" orientation is concerned. However, I think that much of the elegance of the examples that you have given comes from the cleaverness of the classes in the Ruby standard libraries. The cleverness of the "build-in" Ruby classes has always impressed me. I'm talking about operations that work like factory methods for usefull intermediate objects, smart and pervasive use of iterators (what I call the "iterators everywhere" Ruby approach) and other such good implementation choices. The File method to read a file for example. Instead of returning a useless error code (or number of byte read, etc..) they chose to have a read method that returns an object (an array of string I think in this case) that is in fact the content of the file and manage error using exceptions. This is a smart choice because most of the time it will let you work with the content of a file using very few lines of code. The Ruby classes all have that efficient and smart feel and I guess that is what makes Ruby more "verb oriented". Syntactic conveniences like keywords to add getters and setters using one line of code are just icing on the cake. Fortunatly for those of us unable to switch to Ruby much of this "verb orientation" can be emulated by creating our own clever classes. For this to be really practical you need a language with a garbage collector because someone has to cleanup all those intermediate objects. For example: MyTextFile.read("myfile.txt").each_line ___( ___new Operation () ______{ ______public void do (String line) __________{ __________// Do something with line __________} ______}; ___); // I use underlines to make sure everything // is properly indented So what you have is a class MyTextFile that has a factory method read(String filename) that returns an instance of a class that has a each_line(Operation op) method that calls the Operation.do(String line) method for each line of text in the file. Not perfect but more "verb oriented" don't you think. Having closures would avoid having to revert to "name orientation" to define and allocate the Operation instance called in the each_line() method. Now I have to go and start working on my "verb oriented" Java library. Thanks for the nice exchange. JS

apotheon
apotheon

Hopefully the offered Ruby code helps with that, then. I can't vouch for it without looking at it again, and I'm feeling just a touch too lazy to search for it at the moment. Edit -- So much for being lazy. Here's a contrived example: 1. more [b]noun-oriented[/b] [i]class Iterator def initialize(iterating_list) @iterating_list = Array.new(iterating_list) end attr_accessor :iterating_list def iter_8(the_list) for iteration in (0..the_list.length-1) puts the_list.at(iteration) end end end arr = Array.new ['one', 'two', 'three'] list_foo = Iterator.new(arr) list_foo.iter_8(list_foo.iterating_list)[/i] 2. more [b]verb-oriented[/b] [i]class Array def iter_8 yield self end end arr = %w[one two three] arr.iter_8 { |foo| puts foo }[/i] 3. [b]analysis[/b] In more noun-oriented programming, you have to have an object for everything, and you must only make use of that object by specifying it explicitly as you pass it a message. If at all possible, those objects must also use other objects in the same way. In more verb-oriented programming, objects need not be nearly as complex, nor do you need to embed your nonspecific methods in objects so that objects can "own" them. Instead, you can easily construct a simple instruction when needed and pass it to an object for execution. Note that the noun-oriented version would be somewhat more obtuse if written in Java. It's actually difficult to put something like that together in Ruby, and some of the gyrations I went through to impose noun-oriented design on Ruby feel ludicrous within the context of this language. I am, in essence, doing my best to ignore the verb-oriented functionality of the language to provide a noun-oriented look at how something is done. Now let's look at some other examples, borrowed from [url=http://www.rubyrailways.com/sometimes-less-is-more/]here[/url]: 1. [b]noun-oriented Java[/b] [i]if ( 1 % 2 == 1 ) System.err.println("Odd!")[/i] 2. [b]verb-oriented Ruby[/b] [i]if 11.odd? print "Odd!"[/i] In this case, Java suffers a bit from more than noun-orientedness -- there's also Java's issues with primitives of various sorts. Just comparing the println call to the print call, on the other hand, shows something quite clearly about the way an obsessively noun-oriented language can get in your way. There are three discrete syntactic elements to Java's example, as compared with Ruby's one element, just to output a short string. It's bad enough when you have to do that with objects and methods that are provided as part of the language, but when you start needing to define your own classes and methods, and instantiate your own objects, all before you can even type this in, it can get pretty damned ugly. Not only do you tend to end up defining a lot more classes, but each class takes a lot more boilerplate to define, and a lot more "yellow code" (implementation detail, as opposed to "green code" or actual problem abstraction). . . . and again: 1. [b]noun-oriented Java[/b] [i]Class Circle private Coordinate center, float radius; public void setCenter(Coordinate center) { this.center = center; } public Coordinate getCenter() { return center; } public void setRadius(float radius) { this.radius = radius; } public Coordinate getRadius() { return radius; } end;[/i] 2. [b]verb-oriented Ruby[/b] [i]class Circle attr_accessor :center, :radius end[/i] In this instance, a single method takes two arguments in Ruby to do what requires a shotgun blast of method calls to various accessor construction objects in Java. . . . and more: 1. [b]noun-oriented Java[/b] [i]import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Test { public static void main(String[] args) { try { BufferedReader in = new BufferedReader(new FileReader("test.txt")); StringBuffer sb = new StringBuffer(); String str; while ((str = in.readLine()) != null) { sb.append(str + "\n"); } in.close(); String result = sb.toString(); Pattern sentencePattern = Pattern.compile("(.*?\\.)\\s+?"); Pattern javaPattern = Pattern.compile("Ruby"); Matcher matcher = sentencePattern.matcher(result); while (matcher.find()) { String match = matcher.group(); Matcher matcher2 = javaPattern.matcher(match); if (matcher2.find()) System.err.println(match); } catch (IOException e) { e.printStackTrace(); } } } }[/i] 2. [b]verb-oriented Ruby[/b] [i]File.read('test.txt').scan(/.*?\. /).each { |s| puts s if s =~ /Ruby/ }[/i] Here we see where the necessity of chaining objects together in Java to construct the necessary framework for a simple operation can get in the way, and how a block sent to a method (a verb applied to a verb, in other words) can greatly enhance the power and beauty of your code. I thought about writing some more code myself for you, but figured you'd get as much benefit from someone else's code as an example without me having to write it all -- and I would have struggled to make Ruby look noun-oriented as I did in my first examples, rather than using Java. This is better.

jslarochelle
jslarochelle

I guess we all have a masochistic side :)

jslarochelle
jslarochelle

Since I actually use Ruby for tools and quick internal jobs it was easy for me to go back and look at the example given in this thread (the branches on closures for example). I think I get the general idea. JS

Justin James
Justin James

I didn't feel lectured. :) But I do know what you mean. Today I took a stroll through our "snakepit" and caught two of our three developers not using version control, after I worked extra hours to check a TON of old stuff in! I wanted to kill them, especially since I was up until 4 AM Friday night working on a a project, and an hour of that 4 hour project was lost due to the speed of using VSS over a VPN at home, and another hour was due to issues caused by my home directory being located on the network (first time I used Visual Studio with the files directly on the network... a real shock). So the project started at midnight due to be completed at 2, lasted until 4. But yes, I know what it is like to be an ignored evangelist... :) I suspect you are masochistic, but no more so than I am. I choose to abuse myself in different ways (remember, I am doing MT in VB.Net, and VB.Net is bad enough and MT makes it worse). I swear, VB.Net is like an illegal drug. You try a touch of it, it gives you an instant result that I was taught I had to work hard for, but then the crash comes 15 minutes later, and I realize that my "friend" VB.Net is really destroying my life... and I keep using it time and time again... for me, my hidden mental sickness is that I am willing to put up with the misery of doing "real work" in VB.Net for the ease of doing the dinky parts in VS.Net, and I am too lazy to just write some classes in C# most of the time... J.Ja

apotheon
apotheon

"[i]I understand your point but I have a hard time seing how a language could be extended to be more 'verb oriented' or what a pure 'verb oriented' language would look like.[/i]" A language generally shouldn't be "pure" in its verb orientation any more than it should be "pure" in its noun orientation. I don't think anyone here advocated for [b]purity[/b] in verb orientation -- just that a language be more verb oriented than noun oriented. It's not so tough to figure out how a language could be [b]more[/b] verb oriented, by the way. Just learn Ruby enough so that you understand how to use its constructs and idioms effectively, as you have for Java. Ruby shouldn't take nearly as long to learn to a degree needed to appreciate its verb-oriented form as it did to learn Java to a similar degree, however. I'm not saying you have to like Ruby, by the way -- just that, in absence of better ideas, I think that might be, for someone in your position, the fastest and most useful means of pursuing the goal of understanding more verb-oriented OOP techniques.

jslarochelle
jslarochelle

I wanted to describe that maybe I became blind to the limitation of the noun orientation because I gained so much from it. The fact that I still have to play OOP evangelist at work probably did'nt help in the way I expressed this. I understand your point but I have a hard time seing how a language could be extended to be more "verb oriented" or what a pure "verb oriented" language would look like. Maybe I should look at some of the alternate languages mentioned in this and other thread. The bottom line for me however (and this goes back to your original question) is that multithreading does not feel that bad in Java for me. Maybe I'm masochistic ? JS

Justin James
Justin James

I agree wholeheartedly that OO and the related architecture and practices are of huge benefit to the development process! My real objection is that in some languages (Java, C#, VB.Net, etc.), the OO paradigm goes so far, that ease of use at a syntax level is sacrificed on the alter of consistency with the noun-orientation. I am sure that Java's threading libraries work great; .Net Framework's threading libraries are quite extensive, comprehensive, and reliable. The failure, in my mind, is that the syntax makes writing, debugging, and testing the code pure misery, and the syntax is driven by a desire for consistency with a syntax model that makes no sense. Let's image what a loop looks like when carried to it's logical conclusion in the noun-based OO world: Microsoft.VisualBasic.Statements.Loops.For(0, 10, AddressOf(intCounter), AddressOf(funcCodeIWantToIterate) Pretty ugly, isn't it? But that is exactly what the folks who bring us garbage like the current threading model in .Net want us to be doing. After all, "for" is no good, it is a statement. And if there is a "for" statement, people could start writing all sorts of functions and procedures and extending the language itself, instead of building classes and "frameworks" and the sky will fall! Of course, it really is not that bad... I have not yet met a strice OO advocate who proposes the abolition of the "for" statement in favor of a loop class with a "for" method. But if loop constructors and logic statements can reside at the statement level, why not some other generic items like threading/locking? J.Ja

Justin James
Justin James

You bring up something I have not really thought about much before, but you are right. Closures do provide a very high degree of safety between threads. I've used them in the past to safely isolate "dangerous" code from the rest of the program (as a sort of in-code jail()), but it never occured to me to use them precisely for the purpose of code isolation in threading. If I have some free time (not bloody likely) I will play with this a bit in C#, since VB.Net does not support closures until .Net 3.5, and I don't want to install beta .Net. :) J.Ja

Mark Miller
Mark Miller

re: object-oriented I think you've got this right. The idea is that an object should have full control over how it does things internally--its implementation, even receiving messages. An object fully encapsulates its own state. There is no coupling between its class implementation and that of other classes, except via. inheritance. There is usually tight coupling with an object's [i]relationship[/i] to other objects, though it's not forced into this. I think the current implementation of Smalltalk (80) kind of takes away the control over receiving messages, because there's a mechanism built into every object telling it how to receive messages. A trick Smalltalk programmers use to get around this is they define a #doesNotUnderstand (DNU) message handler. This message is automatically sent to the receiver anytime you send a message the object doesn't understand. This method receives the incoming message as an object, along with its parameters. It can then translate that message into whatever action it wants. So developers use this by not defining some methods in their classes, but just setting this up to define their own message handling semantics. Kind of convoluted, and I'm sure Kay would complain about it himself. I've heard Ruby has a similar mechanism. One of the things I've heard Kay talk about is in 1976 he kind of split off from the Smalltalk project at Xerox, and professional developers took over its development. In his opinion they kind of screwed up his original idea. It's still good, just not as good as he thought it should be. The earlier versions of Smalltalk (76 and earlier) were fully capable of parsing their own message streams, accepting or rejecting messages outright, without jumping through hoops. What I'd add to your analysis, and this is what Kay emphasizes with programming an object system: the abstraction is in the messages, not in the objects. Objects contain state and implementation (ie. non-abstract things), though I believe I've heard him say that there shouldn't be such an emphasis on maintaining state inside objects. Instead the focus should be on computation through message passing. This certainly doesn't mean that objects should be stateless. My guess is he's trying to steer people away from the traditional OOP practice of making objects the center of attention. The focus should be on the relationships between objects. It should be on designing semantically meaningful messages, and meaningful relationships between objects. He wants to get people focusing more on software architecture than trying to pound out code. One thing I haven't quite figured out yet is he says the one thing objects DO abstract is the concept of a computer. He says every single object is a computer in and of itself, capable of doing everything a computer can do. My guess at this point is he means this in the sense of a Turing machine. Once you get this analogy, you can begin to see that programming in an object system is kind of like using distributed computation on the internet, except that it's synchronous (unless the message receiving semantics are defined otherwise). You can think of each object as a server or client, passing messages between each other. One part I loved in a speech he gave 10 years ago is when he said that "There is not one single atom in the internet today that existed when the internet (ARPANet) was created. There is not one single line of code in the internet today that existed when it was created." He went on to say the internet has been running for more than 2 decades, "and has [b][i]never had to stop![/i][/b]" He said this is the way we have got to start thinking about the software systems we create. Perhaps he was thinking about this WRT the Y2K crisis that was still looming back then. He was trying to make the point that late binding is not just a neato feature of an object system, but there was in fact a real, essential goal in mind that went into creating it. re: selector Just so we're clear, one thing he did say in our conversation was when he talked about "a[5]" he was talking in terms of a language that implements arrays (Smalltalk doesn't, but it emulates them). So he wasn't trying to say that "+" is like "[]". That's the mistake I made. What he was saying was that when "3" is passed the message "+", "3" indexes into its set of methods, using "+" as it's index, and finds the correlated "add" action, just like "a" finds the 5th element in its array when it's passed "5" as an index. He was talking solely about the index referencing that's going on.

apotheon
apotheon

[b]re: "object oriented" --[/b] That's an entirely plausible explanation for why Alan Kay coined the term "object oriented" in the first place. I'd buy it for a dollar -- especially since OOP really is both object-oriented and message oriented, in that you build objects but it's the messages you pass them (and that they pass each other) that make it a program rather than just a bunch of building blocks. Ever since I first ran across that quote of his, I've been trying to reconcile the notion that it should have been called "message oriented programming" with the fact that you're still passing the messages to the objects, and it's the objects that execute the methods those messages name. The more direct conceptual separation of the system from the process (the class hierarchy from the messages passed, with the objects as both implementations and implementors), the more it all makes sense. In other words, it's message oriented programming not because it's all about the messages, but because defining program execution is about the messages -- and defining the system within which these messages are passed is what's really object oriented. [b]re: "selector" --[/b] I hadn't really made the conscious connection between arithmetic operators like `+` and selector operators like `[]` before, but I had definitely already reached the point where I viewed them both in the manner toward which Alan Kay seemed to be leading things when he started talking about an arithmetic operator being a selector. I credit Ruby with providing me that insight, because of the fact that in Ruby the idea that `+` and `[]` are in fact methods rather than primitive operators sorta creates that kind of Grand Unified Theory of Operators understanding quite naturally. I just wouldn't have thought of going back to the concept of a "selector" to explain it. In case that was only as clear as mud, in Ruby this: a[5] + 1 is basically syntactic sugar for this: a.[](5).+(1) Once you start figuring out things about Ruby like that, it's kinda difficult to [b]fail[/b] to see selector and arithmetic operators as being roughly identical types of syntactic constructs, under the hood -- at least within the context of a "pure" object oriented language like Ruby (or Smalltalk). In one sense, calling an arithmetic operator like the addition operator a "selector" seems a little like going backwards, because you're trying to explain message passing in terms of imperative programming primitive operators. In another sense, though, it seems to be a valuable way to view message passing in general -- because you're passing a "selector" of sorts to an object as a message, and the object is using that to [b]select[/b] a method in its repertoire to execute. Kinda brilliant that way, especially in how it can help to bootstrap understanding of how message passing works in (good) OOP for someone whose background is firmly rooted in imperative/procedural programming.

Justin James
Justin James

Everything I've read about him or from him has arrived to me through Mark's blog (which you should probably check out: tekkie.wordpress.com). It's why I started getting more concerned with things like the relationship between language syntax and how we approach the code writing process, which in turn has helped me understand a lot more about programming in general. J.Ja

Justin James
Justin James

In that scenario, processes make sense, because you are using them as message queues. And message queues are a hallmark of big, enterprise-y, networked systems. Even within a single application, process forking is a lot easier to work with than threading. But threading can do a lot of stuff that is a pain with processes. It's all about the coupling. The *Nix process and pipe model rocks for tasks that are extremely loosely coupled. Grep is a great example... generic input, configurable output, and used in a ton of places. For for something really specialized where tight coupling is not a hinderance to future use, threading has a lot to offer. At the end of the day, once you start doing all of the IPC stuff, threads and processing are of about equal amounts of work, regardless of how you slice it. J.Ja

apotheon
apotheon

. . . but for most purposes, people in circles I frequent talk about concurrency for high-traffic, high-load networked systems -- where the only argument against multiprocess concurrency is overhead (not much of a benefit in this case) and the arguments against multithreaded concurrency are various and sundry (such as "holy crap, this is hard to write so I don't get a race condition").