The intent is there, the accomplishment is there. The only bummer is the notation of the query language itself. Who wants to write code like that?
Whatever your political stripes, if you are an American who believes the airwaves are still a public resource, do all of us a favor and participate in this brief boycott of CBS.
Remember, the airwaves are licensed and renewed by the public to CBS. They are not privately owned.
Michael is examining some code in Smalltalk and C. Here it is...
" The original Smalltalk example. "
canvas displayLineFrom: (topPoint x - gibDistance @ topPoint y) to: (topPoint + 1).
/* The original C example. */
canvas.displayLineFrom_to( Point.asPoint(topPoint.x() - gibDistance, topPoint.y()), topPoint.MoveBy(1,1));
I would not hesitate to use the "Descriptive Temporary" pattern. (Is there one? Maybe there should be.) Taking this to the extreme, I might end up with something like the following in Smalltalk and C, respectively. Keeping to short methods, I would not have much more code than this in a single method or function. I think this style, while longer, is easier on my brain...
" The Smalltalk example with descriptive temporaries. "
x := topPoint x - gibDistance
y := topPoint y
lineBegin := x @ y
lineEnd := topPoint + 1
canvas displayLineFrom: lineBegin to: lineEnd.
/* The C example with descriptive temporaries. */
int x = topPoint.x() - gibDistance;
int y = topPoint.y();
Point lineBegin = new Point(x, y);
Point lineEnd = topPoint.MoveBy(1, 1);
Now, this also has the effect of making Smalltalk more readable than C since there is less line noise. But I learned Smalltalk before I learned C.
Ted Neward anticipates solutions to runtime downloads, DLL hell, and other nightmares, realizing Java is in a similar boat...
And lest anybody start to think otherwise, the JVM presents the same problem as the .NET Runtime, and when we solve the .NET Runtime versioning issues, we'll have solved the JVM ones, using the same solution.
The linking problem has been solved for Java... there is the GNU Compiler for Java, as well as commercial native Java compilers. JNLP is intended to solve versioning problems. I have used it, but never in the presence of versioning problems.
The bigger answer is time. Systems will thrash less as they mature. This is for better or worse, since the ability to change even undesirable features is inversely proportional to the number of dependencies applications have on them.
Now is a good time to bring up a theme of mine: the software world has a few examples of highly dynamic systems; the rest are evolving to become more like them, truly. Now is a good time to point out that highly dynamic systems like Lisp and Smalltalk have a long, proven history of backwards compatibility:
If your application requires a feature that comes out of the box in another dialect or from a previous version, chances are good you can take that feature with you to a new dialect or version. If you wish the root class Object had a feature the vendor did not think to include, you can add it yourself just in the applications that you designate.
this stuff is being integrated at the platform and framework levels on both the MS and non-MS side so that developers can no only take advantage of it without having to understand all the nitty-gritty details, but also gain maximal benefits with minimal code.
There be dragons.
I'm getting punchy. I better go.
Good points on all sides of the ongoing debate on messages and objects and distributed systems.
I will just add one observation...
Dropping a feature is not the same thing as fixing a feature.
Much lamenting of the perils of using inheritance in an OO language. But these perils are part of a well worn path. Take heart and remember to learn from the mistakes of others,
White Box and Black Box frameworks... it's a matter of evolution.
I can only whine a bit in response to this desire to create new flow of control sytax.
Yesterday I posted a new way to define functions and their tests contiguously using a new syntax in Scheme. It took about 10 minutes and less than 10 lines of code.
Likewise in Lisp as well as Smalltalk defining new control structures is childs play, mainly because the control structures in those languages are defined using the very same mechanisms that are available to you, the dear programmer.
Yes, I know, I am a loser to even bring this up.
I'm recalling something for the the dotnet reality check...
Because dotnet is a more "complete" object model than COM (inheritance and shadowing of public and private aspects) and because different languages (VB.NET and C# to name two) have somewhat different rules for inheritance, it may be that dotnet has more interop problems than COM. I couldn't say because I don't know COM.
A problem with dotnet inheritance was documented some time ago. I don't believe it has been fixed.
What is really needed in language neutrality? A few thoughts:
There is no reason why one could not build a Longhorn on this "less is more" model, and the result would have more potential (flexibility, scalability) than the one that appears on the horizon, as far as I can see.
A thread of conversation on the agile-testing yahoo group is speculating on the ability to define a function and its tests "contiguously" to reduce the effort to make the contextual switch between "coding" and "testing".
Here is a simple Scheme macro to approximate the idea...
; The following is a macro that allows you to supply test input and
; test results when you define a function. After the function is
; defined, the tool automatically runs the function on the test input
; and checks to see if it matches the expected result. There are a
; number of enhancements (list of test inputs, define test function,
; etc.) to consider.
(defmacro define-eg (name-result parameter-input . body)
(let ((name (car name-result))
(eg-result (cadr name-result))
(parameters (map (lambda (p) (car p)) parameter-input))
(eg-input (map (lambda (p) (cadr p)) parameter-input)))
`(begin (define (,name ,@parameters)
(equal? ,eg-result (,name ,@eg-input)))))
(define-eg (product-of-sums 108) ((a 5) (b 7) (c 9))
(* (+ a b) c))
> (load "define-eg.scm")
> (define-eg (product-of-sums 108) ((a 5) (b 7) (c 9)) (* (+ a b) c))
> (product-of-sums 5 7 9)
> (define-eg (bad-product-of-sums 108) ((a 5) (b 7) (c 9)) (+ (* a b) c))
> (bad-product-of-sums 5 7 9)
Robert Martin (home, blog) in Software Development magazine provides a simply useful introduction to PERT charts, Critical Paths, and a couple of simple tools to replace them for software project management.
This presentation is worth reading on two levels:
BTW the ideas in Design By Contract are useful for defining services in general.
...when up to half of the output of a full-blown TDD-style project can be test code, we’re going to want to find ways to automate and streamline the effort.
We have to make a distinction about what kinds of tests we're writing and what kinds of tests we want to automate.
The TDD tests should be just enough to get to a satisfactory design. Depending on the system being constructed, you should still consider acceptance tests, including performance tests and more complete suites for functional coverage than were needed just for the design process.
We don't want to "over automate" the TDD tests since they are programmer tests, i.e. a programmer's tool for thinking.
We do want to automate the validation and verification tests because we want to eliminate boredom and error, allowing the V&V team to spend their time on activities like creative exploratory tests.
I guess I agree with Brian Marick's code reading style more than Richard Gabriel's. Rather than using an optional private parameter in a public function, though, I prefer to use the "named"
let, with an accumulator there, for tail recursive functions.
Is it idiomatic? It's fairly common in Scheme. I am not sure why it has not been adopted more widely into Common Lisp.
;; Richard Gabriel's Idiomatic Common Lisp
(defun fact (n)
(labels ((f (n acc)
(if (<= n 1) acc (f (- n 1) (* n acc)))))
(f n 1)))
;; My (Idiomatic?) Scheme
(define (fact n)
(let loop ((n n) (acc 1))
(if (<= n 1)
(loop (- n 1) (* n acc)))))
;; "Old School" Common Lisp
(defun fact(n &optional (acc 1))
(if (<= n 1)
(fact (- n 1) (* n acc)))
As PDA hardware gains more GHz and MB, attaching large monitors, keyboards, and mice directly to the cradle makes a great deal of sense.
I would think this makes much more sense than a table PC for a large number of users. Well, me.
Why is composition not good enough? Or if not, why is inheritance not the next best thing? I have yet to see a rationale for introducing another mechanism for organizing object-oriented code.