"Strong typing vs. strong testing"

66 views
Skip to first unread message

Scott L. Burson

unread,
Sep 23, 2010, 1:26:20 AM9/23/10
to
This might have been mentioned here before, but I just came across it: a
2003 essay by Bruce Eckel on how reliable systems can get built in
dynamically-typed languages. It echoes things we've all said here, but
I think it's interesting because it describes a conversion experience:
Eckel started out in the strong-typing camp and was won over.

https://docs.google.com/View?id=dcsvntt2_25wpjvbbhk

-- Scott

Kenneth Tilton

unread,
Sep 23, 2010, 12:09:03 PM9/23/10
to

Yes, we noted that at the time. Some cynic suggested Eckel was just
re-positioning himself to sell more books and consulting to everyone
jumping on The Next Big Thing (XP and lightweight languages). Of course
he was also right in what he wrote, so we'll never know. :)

kt


--
http://www.stuckonalgebra.com
"The best Algebra tutorial program I have seen... in a class by itself."
Macworld

TheFlyingDutchman

unread,
Sep 27, 2010, 1:52:38 AM9/27/10
to

If you are writing a function to determine the maximum of two numbers
passed as arguents in a dynamic typed language, what is the normal
procedure used by Eckel and others to handle someone passing in
invalid values - such as a file handle for one varible and an array
for the other?

RG

unread,
Sep 27, 2010, 2:28:38 AM9/27/10
to
In article
<7df0eb06-9be1-4c9c...@q16g2000prf.googlegroups.com>,
TheFlyingDutchman <zzbb...@aol.com> wrote:

The normal procedure is to hit such a person over the head with a stick
and shout "FOO".

rg

Pascal J. Bourguignon

unread,
Sep 27, 2010, 3:58:01 AM9/27/10
to
RG <rNOS...@flownet.com> writes:

Moreover, the functions returning the maximum may be able to work on
non-numbers, as long as they're comparable. What's more, there are
numbers that are NOT comparable by the operator you're thinking about!.


So to implement your specifications, that function would have to be
implemented for example as:


(defmethod lessp ((x real) (y real)) (< x y))
(defmethod lessp ((x complex) (y complex))
(or (< (real-part x) (real-part y))
(and (= (real-part x) (real-part y))
(< (imag-part x) (imag-part y)))))

(defun maximum (a b)
(if (lessp a b) b a))


And then the client of that function could very well add methods:

(defmethod lessp ((x symbol) (y t)) (lessp (string x) y))
(defmethod lessp ((x t) (y symbol)) (lessp x (string y)))
(defmethod lessp ((x string) (y string)) (string< x y))

and call:

(maximum 'hello "WORLD") --> "WORLD"

and who are you to forbid it!?

--
__Pascal Bourguignon__ http://www.informatimago.com/

TheFlyingDutchman

unread,
Sep 27, 2010, 4:46:57 AM9/27/10
to
On Sep 27, 12:58 am, p...@informatimago.com (Pascal J. Bourguignon)
wrote:
> RG <rNOSPA...@flownet.com> writes:
> > In article
> > <7df0eb06-9be1-4c9c-8057-e9fdb7f0b...@q16g2000prf.googlegroups.com>,
> __Pascal Bourguignon__                    http://www.informatimago.com/- Hide quoted text -
>
> - Show quoted text -

in C I can have a function maximum(int a, int b) that will always
work. Never blow up, and never give an invalid answer. If someone
tries to call it incorrectly it is a compile error.
In a dynamic typed language maximum(a, b) can be called with incorrect
datatypes. Even if I make it so it can handle many types as you did
above, it could still be inadvertantly called with a file handle for a
parameter or some other type not provided for. So does Eckel and
others, when they are writing their dynamically typed code advocate
just letting the function blow up or give a bogus answer, or do they
check for valid types passed? If they are checking for valid types it
would seem that any benefits gained by not specifying type are lost by
checking for type. And if they don't check for type it would seem that
their code's error handling is poor.

Pascal Costanza

unread,
Sep 27, 2010, 6:57:38 AM9/27/10
to
On 27/09/2010 10:46, TheFlyingDutchman wrote:
> in C I can have a function maximum(int a, int b) that will always
> work. Never blow up, and never give an invalid answer. If someone
> tries to call it incorrectly it is a compile error.
> In a dynamic typed language maximum(a, b) can be called with incorrect
> datatypes. Even if I make it so it can handle many types as you did
> above, it could still be inadvertantly called with a file handle for a
> parameter or some other type not provided for. So does Eckel and
> others, when they are writing their dynamically typed code advocate
> just letting the function blow up or give a bogus answer, or do they
> check for valid types passed? If they are checking for valid types it
> would seem that any benefits gained by not specifying type are lost by
> checking for type. And if they don't check for type it would seem that
> their code's error handling is poor.

Another alternative is that you don't have a lot of experience with
dynamically typed languages.

The OP provided a link, behind which you can find even more links, and
they already answer all your questions. Reading them helps.


Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/

TheFlyingDutchman

unread,
Sep 27, 2010, 8:12:51 AM9/27/10
to

I don't see where either Bruce Eckel or Robert Martin address the
issue of what to do inside a function when they receive a variable of
an incorrect type. Martin claims that his unit testing has eliminated
the need for him to check for types. Apparently he is claiming he is
sure that his higher level code will never call maximum() with
incorrect types because he tested for all cases now and forever of
that occurring. But it appears he hasn't tested handling incorrect
types since he feels it won't happen. Or, if he has - how does he
handles it isn't stated. Reading his and Eckel's paragraphs didn't
help me see how they handle invalid types inside a function.

Pascal Costanza

unread,
Sep 27, 2010, 8:19:11 AM9/27/10
to
On 27/09/2010 14:12, TheFlyingDutchman wrote:
> On Sep 27, 3:57 am, Pascal Costanza<p...@p-cos.net> wrote:
>> On 27/09/2010 10:46, TheFlyingDutchman wrote:
>>
>>> in C I can have a function maximum(int a, int b) that will always
>>> work. Never blow up, and never give an invalid answer. If someone
>>> tries to call it incorrectly it is a compile error.
>>> In a dynamic typed language maximum(a, b) can be called with incorrect
>>> datatypes. Even if I make it so it can handle many types as you did
>>> above, it could still be inadvertantly called with a file handle for a
>>> parameter or some other type not provided for. So does Eckel and
>>> others, when they are writing their dynamically typed code advocate
>>> just letting the function blow up or give a bogus answer, or do they
>>> check for valid types passed? If they are checking for valid types it
>>> would seem that any benefits gained by not specifying type are lost by
>>> checking for type. And if they don't check for type it would seem that
>>> their code's error handling is poor.
>>
>> Another alternative is that you don't have a lot of experience with
>> dynamically typed languages.
>>
>> The OP provided a link, behind which you can find even more links, and
>> they already answer all your questions. Reading them helps.
>>
>> Pascal
>>
>> --
>> My website:http://p-cos.net
>> Common Lisp Document Repository:http://cdr.eurolisp.org
>> Closer to MOP& ContextL:http://common-lisp.net/project/closer/

>
> I don't see where either Bruce Eckel or Robert Martin address the
> issue of what to do inside a function when they receive a variable of
> an incorrect type. Martin claims that his unit testing has eliminated
> the need for him to check for types. Apparently he is claiming he is
> sure that his higher level code will never call maximum() with
> incorrect types because he tested for all cases now and forever of
> that occurring. But it appears he hasn't tested handling incorrect
> types since he feels it won't happen. Or, if he has - how does he
> handles it isn't stated. Reading his and Eckel's paragraphs didn't
> help me see how they handle invalid types inside a function.

Yes, you're right, you don't see how this issue is addressed. It's a
good idea to get some practice with a dynamically typed language, and
then you will see that it's actually not an issue. Stop guessing.

Pascal Bourguignon

unread,
Sep 27, 2010, 8:29:54 AM9/27/10
to
TheFlyingDutchman <zzbb...@aol.com> writes:

> in C I can have a function maximum(int a, int b) that will always
> work. Never blow up, and never give an invalid answer. If someone
> tries to call it incorrectly it is a compile error.
> In a dynamic typed language maximum(a, b) can be called with incorrect
> datatypes. Even if I make it so it can handle many types as you did
> above, it could still be inadvertantly called with a file handle for a
> parameter or some other type not provided for. So does Eckel and
> others, when they are writing their dynamically typed code advocate
> just letting the function blow up or give a bogus answer, or do they
> check for valid types passed? If they are checking for valid types it
> would seem that any benefits gained by not specifying type are lost by
> checking for type. And if they don't check for type it would seem that
> their code's error handling is poor.


The type of the parameters can be infered by what is done with these
parameters.

In:

(defun m (a b) (< a b))

I don't need to specify the types of a and b, because I, my fellow
programmers, and the implementation can infer that the expected types
are those that are expected by <.

Since < is a generic function that accepts a wide range of types (from
fixnum to real, passing by ratios, floating-point numbers, bigints,
etc), my function m is implicitely generic.

In dynamically typed programming language, you are effectively writting
generic functions by default.


Why do you want to restrict your maximum function to integers modulo
2^W? Since you already have done the hard work of finding the greatest
of two values in an ordered set, why not reuse this hard work for ANY
ordered set?


In almost all instances, type specfications in statically typed
programming language are too strongs, and too early. This is how you
crash rockets! (cf. Ariane-5).


--
__Pascal Bourguignon__
http://www.informatimago.com

Piotr Chamera

unread,
Sep 27, 2010, 10:27:02 AM9/27/10
to
W dniu 2010-09-27 14:12, TheFlyingDutchman pisze:
>
> (...) Reading his and Eckel's paragraphs didn't

> help me see how they handle invalid types inside a function.

They don't handle it inside a function – system throws exception and You
have a chance to handle it in a way You like (close whole system,
or just ignore one user input...).

In static system if something like that happens You have „core dump”
or bad results without warning :)

Pavel Lepin

unread,
Sep 27, 2010, 11:00:38 AM9/27/10
to

Dear Sir,

Please accept my unending awe and admiration, as this has to be the single
dumbest thing I've heard in my life; so, in fact, extraordinary in its
sheer stupidity and perversion of the natural order of the universe, that
until just a few minutes back I wouldn't have believed such utterance to
even be conceivable by an intelligent human being.

Thus remaining your humble and most obd't servant,

--
Pavel Lepin

Norbert_Paul

unread,
Sep 27, 2010, 11:23:44 AM9/27/10
to
Pascal J. Bourguignon wrote:
> Moreover, the functions returning the maximum may be able to work on
> non-numbers, as long as they're comparable. What's more, there are
> numbers that are NOT comparable by the operator you're thinking about!.

How about something like

(defun mymax (predicate &rest args)
(do-stuff-more-efficient-but-equivalent-to
(first (sort (copy-list args predicate))))

(defun mymin (predicate &rest args)
(apply #'mymax (complement predicate) args))

?

Then you can define your own maxes and mins using curry or

(defun nummax (a b) (mymax #'< a b))
(defun foomax (a b) (mymax #'foo< a b))
...

and you could delegate argument type checking to the predicate.

Norbert

Norbert_Paul

unread,
Sep 27, 2010, 11:34:21 AM9/27/10
to

OK, but sometimes it is handy to have the possibility to make compile-time
assertions which prevent you from commiting easily avoidable simple mistakes.

For example being able to declare an integer variable r as being of "row-index-type"
and another, say c, as being of "column-index-type" such that

(aref matrix r c)

would pass compilation
but if you confused it with

(aref matrix c r)

some condition (error or warning) would be signalled at compile-time.

I'd consider such a possibility handy -- sometimes.

Norbert

Scott L. Burson

unread,
Sep 27, 2010, 12:21:56 PM9/27/10
to
Norbert_Paul wrote:
>
> OK, but sometimes it is handy to have the possibility to make compile-time
> assertions which prevent you from committing easily avoidable simple
> mistakes.

Agreed. I actually don't see this issue in black and white terms; I've
written lots of Lisp, and I've written lots of code in statically typed
languages, and they all have advantages and disadvantages. In the end
it all comes back to my time: how much time does it take me to ship a
debugged system? Working in Lisp, sometimes I don't get immediate
feedback from the compiler that I've done something stupid, but this is
generally counterbalanced by the ease of interactive testing, that
frequently allows me to run a new piece of code several times in the
time it would have taken me to do a compile-and-link in, say, C++.

So while I agree with you that compiler warnings are sometimes handy,
and there are occasions, working in Lisp, that I would like to have more
of them(*), it really doesn't happen to me very often that the lack of
one is more than a minor problem.

(*) Lisp compilers generally do warn about some things, like passing the
wrong number of arguments to a function, or inconsistent spelling of the
name of a local variable. In my experience, these warnings cover a
substantial fraction of the stupid mistakes I actually make.

-- Scott

Scott L. Burson

unread,
Sep 27, 2010, 12:44:24 PM9/27/10
to

Ah, good. I would have been disappointed if my post hadn't kicked off a
discussion :)

To answer your question: what a function does with its arguments is to
pass them to other functions; at some point an argument must be passed
to some built-in Lisp primitive in order to do something with it. Lisp
primitives do their own runtime type checking, so if you try to add a
file handle to an array, for instance, the addition operator will signal
an error.

So the normal procedure is simply to let the Lisp primitives signal
errors in these cases. This actually works pretty well in practice.
Yes, sometimes it is not trivial to relate the error message back to the
coding mistake. But the popular statically-typed languages actually
have a similar problem in that (for example) they don't have different
static types for pointers that can be null and pointers that can't be
null. The consequence is that it's always possible for a coding mistake
to cause the code to dereference a null pointer, since this error is
checked for only at runtime. Tracking down such errors isn't always
fun, of course, but the point is that the vast majority of programmers
work in languages in which not all errors can be detected at compile time.

Although null pointer dereferences actually can be prevented statically
(languages in the ML family take an approach that permits this),
uncomputability considerations guarantee that there are always errors
that can be detected only at runtime. So the fact is, everybody lives
with runtime checking to some extent.

-- Scott

George Neuner

unread,
Sep 27, 2010, 1:05:29 PM9/27/10
to

To be fair ... in every static typed language I know of (including C)
you have to do something to override the type system in order to pass
a value of the wrong type. Of course, the various languages differ
greatly in how easy, or hard, it is to do that.

George

Pascal J. Bourguignon

unread,
Sep 27, 2010, 1:10:49 PM9/27/10
to
Norbert_Paul <norbertpau...@yahoo.com> writes:

Indeed. This is the functional way, vs. the OO way previously
presented.

namekuseijin

unread,
Sep 27, 2010, 1:25:49 PM9/27/10
to

LOLZ

namekuseijin

unread,
Sep 27, 2010, 1:46:32 PM9/27/10
to
> > __Pascal Bourguignon__                    http://www.informatimago.com/-Hide quoted text -

>
> > - Show quoted text -
>
> in C I can have a function maximum(int a, int b) that will always
> work. Never blow up, and never give an invalid answer. If someone
> tries to call it incorrectly it is a compile error.
> In a dynamic typed language maximum(a, b) can be called with incorrect
> datatypes. Even if I make it so it can handle many types as you did
> above, it could still be inadvertantly called with a file handle for a
> parameter or some other type not provided for. So does Eckel and
> others, when they are writing their dynamically typed code advocate
> just letting the function blow up or give a bogus answer, or do they
> check for valid types passed? If they are checking for valid types it
> would seem that any benefits gained by not specifying type are lost by
> checking for type. And if they don't check for type it would seem that
> their code's error handling is poor.

that is a lie.

Compilation only makes sure that values provided at compilation-time
are of the right datatype.

What happens though is that in the real world, pretty much all
computation depends on user provided values at runtime. See where are
we heading?

this works at compilation time without warnings:
int m=numbermax( 2, 6 );

this too:
int a, b, m;
scanf( "%d", &a );
scanf( "%d", &b );
m=numbermax( a, b );

no compiler issues, but will not work just as much as in python if
user provides "foo" and "bar" for a and b... fail.

What you do if you're feeling insecure and paranoid? Just what
dynamically typed languages do: add runtime checks. Unit tests are
great to assert those.

Fact is: almost all user data from the external words comes into
programs as strings. No typesystem or compiler handles this fact all
that graceful...

Pascal J. Bourguignon

unread,
Sep 27, 2010, 1:46:22 PM9/27/10
to
George Neuner <gneu...@comcast.net> writes:

> On Mon, 27 Sep 2010 16:27:02 +0200, Piotr Chamera
> <piotr_...@poczta.onet.pl> wrote:
>
>>W dniu 2010-09-27 14:12, TheFlyingDutchman pisze:
>>>
>>> (...) Reading his and Eckel's paragraphs didn't
>>> help me see how they handle invalid types inside a function.
>>
>>They don't handle it inside a function – system throws exception and You
>>have a chance to handle it in a way You like (close whole system,
>>or just ignore one user input...).
>>
>>In static system if something like that happens You have „core dump”
>>or bad results without warning :)
>
> To be fair ... in every static typed language I know of (including C)
> you have to do something to override the type system in order to pass
> a value of the wrong type.

C is weakly typed. Moreover:

#include <stdio.h>
#include <stdarg.h>

int sum_int(int n,...){
int v;
va_list ap;
va_start(ap,n);
for(i=0;i<n;i++){
v+=va_arg(ap,int);
}
va_end(ap);
return(v);
}

int main(){
printf("%d\n",sum_int(3,1.2,"trois",4L));
return(0);
}

> Of course, the various languages differ
> greatly in how easy, or hard, it is to do that.

Very easy in C.

Kenneth Tilton

unread,
Sep 27, 2010, 3:16:37 PM9/27/10
to

That's where the "strong testing" alternative comes in: when the test
that hits that code runs, the program breaks. Fix it. The obvious
challenge is writing compleat tests, the obvious call being made is that
that is more cost-effective than wrestling with strong static type
checking compilers.

Pascal J. Bourguignon

unread,
Sep 27, 2010, 3:29:44 PM9/27/10
to
namekuseijin <nameku...@gmail.com> writes:


I would even go further.

Types are only part of the story. You may distinguish between integers
and floating points, fine. But what about distinguishing between
floating points representing lengths and floating points representing
volumes? Worse, what about distinguishing and converting floating
points representing lengths expressed in feets and floating points
representing lengths expressed in meters.

If you start with the mindset of static type checking, you will consider
that your types are checked and if the types at the interface of two
modules matches you'll think that everything's ok. And six months later
you Mars mission will crash.

On the other hand, with the dynamic typing mindset, you might even wrap
your values (of whatever numerical type) in a symbolic expression
mentionning the unit and perhaps other meta data, so that when the other
module receives it, it may notice (dynamically) that two values are not
of the same unit, but if compatible, it could (dynamically) convert into
the expected unit. Mission saved!

Peter Keller

unread,
Sep 27, 2010, 4:09:20 PM9/27/10
to
TheFlyingDutchman <zzbb...@aol.com> wrote:
> in C I can have a function maximum(int a, int b) that will always
> work. Never blow up, and never give an invalid answer. If someone
> tries to call it incorrectly it is a compile error.

Never is a strong word. Implicit type conversion for the win!

maximum(sqrt(-1) , 100); /* oops */

If you change maximum to take floats, the compiler has to runtime check
that neither of them are NaNs. Smells like dynamic typing to me!

-pete

Scott L. Burson

unread,
Sep 27, 2010, 4:36:39 PM9/27/10
to
Pascal J. Bourguignon wrote:
>
> On the other hand, with the dynamic typing mindset, you might even wrap
> your values (of whatever numerical type) in a symbolic expression
> mentionning the unit and perhaps other meta data, so that when the other
> module receives it, it may notice (dynamically) that two values are not
> of the same unit, but if compatible, it could (dynamically) convert into
> the expected unit. Mission saved!

In fairness, you could do this statically too, and without the consing
required by the dynamic approach.

-- Scott

Pascal J. Bourguignon

unread,
Sep 27, 2010, 4:38:17 PM9/27/10
to

I don't deny it. My point is that it's a question of mindset.

TheFlyingDutchman

unread,
Sep 27, 2010, 11:01:37 PM9/27/10
to
On Sep 27, 1:09 pm, Peter Keller <psil...@cs.wisc.edu> wrote:

> TheFlyingDutchman <zzbba...@aol.com> wrote:
> > in C I can have a function maximum(int a, int b) that will always
> > work. Never blow up, and never give an invalid answer. If someone
> > tries to call it incorrectly it is a compile error.
>
> Never is a strong word. Implicit type conversion for the win!
>
> maximum(sqrt(-1) , 100); /* oops */

I don't think that this demonstrates an error _inside_ the maximum
function. Whatever (int) sqrt(-1) gets converted to, the maximum
function will appropriately compare it to 100 and determine which one
is higher. If someone told me that my maximum function (in this case)
was giving them an incorrect answer, I would print out what they were
passing in and show that it returned the correct higher value.

Malcolm McLean

unread,
Sep 28, 2010, 5:13:19 AM9/28/10
to
> that graceful...- Hide quoted text -
>
You're right. C should have a much better library than it does for
parsing user-supplied string input.

The scanf() family of functions is fine for everyday use, but not
robust enough for potentially hostile inputs. atoi() had to be
replaced by strtol(), but there's a need for a higher-leve function
built on strtol().

I wrote a generic commandline parser once, however it's almost
impossible to achieve something that is both useable and 100%
bulletproof.


Malcolm McLean

unread,
Sep 28, 2010, 5:55:19 AM9/28/10
to
On Sep 27, 9:29 pm, p...@informatimago.com (Pascal J. Bourguignon)
wrote:
>

> On the other hand, with the dynamic typing mindset, you might even wrap
> your values (of whatever numerical type) in a symbolic expression
> mentionning the unit and perhaps other meta data, so that when the other
> module receives it, it may notice (dynamically) that two values are not
> of the same unit, but if compatible, it could (dynamically) convert into
> the expected unit.  Mission saved!
>
I'd like to design a language like this. If you add a quantity in
inches to a quantity in centimetres you get a quantity in (say)
metres. If you multiply them together you get an area, if you divide
them you get a dimeionless scalar. If you divide a quantity in metres
by a quantity in seconds you get a velocity, if you try to subtract
them you get an error.

Richard

unread,
Sep 28, 2010, 6:10:26 AM9/28/10
to
Malcolm McLean <malcolm...@btinternet.com> writes:

or simply use c++ etc and simply use overridden operators which pick the correct
algorithm....

--
"Avoid hyperbole at all costs, its the most destructive argument on
the planet" - Mark McIntyre in comp.lang.c

Tim Bradshaw

unread,
Sep 28, 2010, 6:19:55 AM9/28/10
to
On 2010-09-28 10:55:19 +0100, Malcolm McLean said:

> I'd like to design a language like this. If you add a quantity in
> inches to a quantity in centimetres you get a quantity in (say)
> metres. If you multiply them together you get an area, if you divide
> them you get a dimeionless scalar. If you divide a quantity in metres
> by a quantity in seconds you get a velocity, if you try to subtract
> them you get an error.

There are several existing systems which do this. The HP48 (and
descendants I expect) support "units" which are essentially dimensions.
I don't remember if it signals errors for incoherent dimensions.
Mathematica also has some units support, and it definitely does not
indicate an error: "1 Inch + 1 Second" is fine. There are probably
lots of other systems which do similar things.

BartC

unread,
Sep 28, 2010, 6:18:41 AM9/28/10
to

"Malcolm McLean" <malcolm...@btinternet.com> wrote in message
news:1d6e115c-cada-46fc...@c10g2000yqh.googlegroups.com...

As you suggested in 'Varaibles with units' comp.programming Feb 16 2008?
[Yes with that spelling...]

I have a feeling that would quickly make programming impossible (if you
consider how many combinations of dimensions/units, and operators there
might be).

One approach I've used is to specify a dimension (ie. unit) only for
constant values, which are then immediately converted (at compile time) to a
standard unit:

a:=sin(60°) # becomes sin(1.047... radians)
d:=6 ins # becomes 152.4 mm

Here the standard units are radians, and mm. Every other calculation uses
implied units.

--
Bartc

Message has been deleted

Malcolm McLean

unread,
Sep 28, 2010, 9:39:27 AM9/28/10
to
On Sep 28, 12:19 pm, Tim Bradshaw <t...@tfeb.org> wrote:
>
> There are several existing systems which do this.  The HP48 (and
> descendants I expect) support "units" which are essentially dimensions.
>  I don't remember if it signals errors for incoherent dimensions.  
> Mathematica also has some units support, and it definitely does not
> indicate an error: "1 Inch + 1 Second" is fine.  There are probably
> lots of other systems which do similar things.
>
The problem is that if you allow expressions rather than terms then
the experssions can get arbitrarily complex. sqrt(1 inch + 1 Second),
for instance.

On the other hand sqrt(4 inches^2) is quite well defined. The question
is whether to allow sqrt(1 inch). It means using rationals rather than
integers for unit superscripts.

(You can argue that you can get things like km^9s^-9g^3 even in a
simple units system. The difference is that these won't occur very
often in real programs, just when people are messing sbout with the
system, and we don't need to make messing about efficient or easy to
use).


Tim Bradshaw

unread,
Sep 28, 2010, 10:55:26 AM9/28/10
to
On 2010-09-28 14:39:27 +0100, Malcolm McLean said:

> he problem is that if you allow expressions rather than terms then
> the experssions can get arbitrarily complex. sqrt(1 inch + 1 Second),
> for instance.

I can't imagine a context where 1 inch + 1 second would not be an
error, so this is a slightly odd example. Indeed I think that in
dimensional analysis summing (or comparing) things with different
dimensions is always an error.

>
> On the other hand sqrt(4 inches^2) is quite well defined. The question
> is whether to allow sqrt(1 inch). It means using rationals rather than
> integers for unit superscripts.

There's a large existing body of knowledge on dimensional analysis
(it's a very important tool for physics, for instance), and obviously
the answer is to do whatever it does. Raising to any power is fine, I
think (but transcendental functions, for instance, are never fine,
because they are equivalent to summing things with different
dimensions, which is obvious if you think about the Taylor expansion of
a transcendental function).

--tim

Ron Garret

unread,
Sep 28, 2010, 12:46:09 PM9/28/10
to

CL can do this. There is code by Roman Cunis (dated 1991) called
Measures that does exactly this in the Right Way. It even comes with a
parser that lets you do spiffy things like this:

? (+ 1s 1hr)
1hr:0min:1s
? (/ 1hr 1s)
3600
? (* 1μg 1m/s2)
1nN
?

I have an updated version of his code that streamlines it and fixes a
couple of bugs if anyone is interested.

rg

Niklas Holsti

unread,
Sep 28, 2010, 12:52:43 PM9/28/10
to
Albert van der Horst wrote:
> In article <87fwwvr...@kuiper.lan.informatimago.com>,

...
>> I would even go further.
>>
>> Types are only part of the story. You may distinguish between integers
>> and floating points, fine. But what about distinguishing between
>> floating points representing lengths and floating points representing
>> volumes? Worse, what about distinguishing and converting floating
>> points representing lengths expressed in feets and floating points
>> representing lengths expressed in meters.
>
> When I was at Shell (late eighties) there were people claiming
> to have done exactly that, statically, in ADA.

It is cumbersome to do it statically, in the current Ada standard. Doing
it by run-time checks in overloaded operators is easier, but of course
has some run-time overhead. There are proposals to extend Ada a bit to
make a static check of physical units ("dimensions") simpler. See
http://www.ada-auth.org/cgi-bin/cvsweb.cgi/acs/ac-00184.txt?rev=1.3&raw=Y
and inparticular the part where Edmond Schonberg explains a suggestion
for the GNAT Ada compiler.

> A mission failure is a failure of management. The Ariadne crash was.

Just a nit, the launcher is named "Ariane".

--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .

George Neuner

unread,
Sep 28, 2010, 1:16:50 PM9/28/10
to
On Mon, 27 Sep 2010 19:46:22 +0200, p...@informatimago.com (Pascal J.
Bourguignon) wrote:

>George Neuner <gneu...@comcast.net> writes:
>
>> On Mon, 27 Sep 2010 16:27:02 +0200, Piotr Chamera
>> <piotr_...@poczta.onet.pl> wrote:
>>
>>>In static system if something like that happens You have „core dump”
>>>or bad results without warning :)
>>
>> To be fair ... in every static typed language I know of (including C)
>> you have to do something to override the type system in order to pass
>> a value of the wrong type.
>
>C is weakly typed.

But still statically typed.

>Moreover:
>
>#include <stdio.h>
>#include <stdarg.h>
>
>int sum_int(int n,...){
> int v;
> va_list ap;
> va_start(ap,n);
> for(i=0;i<n;i++){
> v+=va_arg(ap,int);
> }
> va_end(ap);
> return(v);
>}
>
>int main(){
> printf("%d\n",sum_int(3,1.2,"trois",4L));
> return(0);
>}

Yes, but just to be clear, this is not an example of *weak* typing.
The vararg/stdarg form technically is untyped ... it's up to the
function to assign type and meaning to arguments passed in the varlist
and determine whether they are valid.


>> Of course, the various languages differ
>> greatly in how easy, or hard, it is to do that.
>
>Very easy in C.

But not terribly difficult in a number of languages.

George

Pascal J. Bourguignon

unread,
Sep 28, 2010, 1:22:12 PM9/28/10
to
Ron Garret <rNOS...@flownet.com> writes:

I'm definitely interested. I have to use something like that in my
current project...

Dan Katz

unread,
Sep 28, 2010, 1:29:42 PM9/28/10
to
On 28 Sep 2010, p...@informatimago.com wrote:

> Ron Garret <rNOS...@flownet.com> writes:
>
>>
>> CL can do this. There is code by Roman Cunis (dated 1991) called
>> Measures that does exactly this in the Right Way. It even comes with
>> a parser that lets you do spiffy things like this:
>>
>> ? (+ 1s 1hr)
>> 1hr:0min:1s
>> ? (/ 1hr 1s)
>> 3600
>> ? (* 1μg 1m/s2)
>> 1nN
>> ?
>>
>> I have an updated version of his code that streamlines it and fixes a
>> couple of bugs if anyone is interested.
>
> I'm definitely interested. I have to use something like that in my
> current project...

Also interested!

Dan

Tamas K Papp

unread,
Sep 28, 2010, 1:32:15 PM9/28/10
to

Me too. Having it in a public repo (eg on github) would be nice.

Tamas

Thomas A. Russ

unread,
Sep 28, 2010, 1:28:08 PM9/28/10
to
Malcolm McLean <malcolm...@btinternet.com> writes:

> I'd like to design a language like this. If you add a quantity in
> inches to a quantity in centimetres you get a quantity in (say)
> metres. If you multiply them together you get an area, if you divide
> them you get a dimeionless scalar. If you divide a quantity in metres
> by a quantity in seconds you get a velocity, if you try to subtract
> them you get an error.

Done in 1992.

See
<http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/syntax/measures/0.html>
citation at <http://portal.acm.org/citation.cfm?id=150168>

and my extension to it as part of the Loom system:
<http://www.isi.edu/isd/LOOM/documentation/loom4.0-release-notes.html#Units>

--
Thomas A. Russ, USC/Information Sciences Institute

RG

unread,
Sep 28, 2010, 2:19:24 PM9/28/10
to
In article <8gen4v...@mid.individual.net>,

OK, it's here for now:

http://www.flownet.com/ron/lisp/units.lisp

It's in kind of a half-baked state at the moment, but it does work.

You'll also need globals.lisp from that same directory. (See

http://rondam.blogspot.com/2009/08/global-variables-done-right.html

for the rationale behind it.)

NOTE: the copyright status of this code is somewhat dubious. The
original code that this is based on is here:

http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/
syntax/measures/0.html

It doesn't have a copyright notice that I could find.

rg

George Neuner

unread,
Sep 28, 2010, 2:21:29 PM9/28/10
to
On 28 Sep 2010 12:42:40 GMT, Albert van der Horst
<alb...@spenarnc.xs4all.nl> wrote:

>I would say the dimensional checking is underrated. It must be
>complemented with a hard and fast rule about only using standard
>(SI) units internally.
>
>Oil output internal : m^3/sec
>Oil output printed: kbarrels/day

"barrel" is not an SI unit. And when speaking about oil there isn't
even a simple conversion.

42 US gallons ? 34.9723 imp gal ? 158.9873 L

[In case those marks don't render, they are meant to be the
double-tilda sign meaning "approximately equal".]

George

Nick

unread,
Sep 28, 2010, 3:12:51 PM9/28/10
to

I didn't go as far as that, but:

$ cat test.can
database input 'canal.sqlite'

for i=link 'Braunston Turn' to '.*'
print 'It is ';i.distance into 'distance:%M';' miles (which is '+i.distance into 'distance:%K'+' km) to ';i.place2 into 'name:place'
end for i
$ canal test.can
It is 0.10 miles (which is 0.16 km) to London Road Bridge No 90
It is 0.08 miles (which is 0.13 km) to Bridge No 95
It is 0.19 miles (which is 0.30 km) to Braunston A45 Road Bridge No 91
--
Online waterways route planner | http://canalplan.eu
Plan trips, see photos, check facilities | http://canalplan.org.uk

Keith Thompson

unread,
Sep 28, 2010, 3:15:07 PM9/28/10
to
George Neuner <gneu...@comcast.net> writes:
> On 28 Sep 2010 12:42:40 GMT, Albert van der Horst
> <alb...@spenarnc.xs4all.nl> wrote:
>>I would say the dimensional checking is underrated. It must be
>>complemented with a hard and fast rule about only using standard
>>(SI) units internally.
>>
>>Oil output internal : m^3/sec
>>Oil output printed: kbarrels/day
>
> "barrel" is not an SI unit.

He didn't say it was. Internal calculations are done in SI units (in
this case, m^3/sec); on output, the internal units can be converted to
whatever is convenient.

> And when speaking about oil there isn't
> even a simple conversion.
>
> 42 US gallons ? 34.9723 imp gal ? 158.9873 L
>
> [In case those marks don't render, they are meant to be the
> double-tilda sign meaning "approximately equal".]

There are multiple different kinds of "barrels", but "barrels of oil"
are (consistently, as far as I know) defined as 42 US liquid gallons.
A US liquid gallon is, by definition, 231 cubic inches; an inch
is, by definition, 0.0254 meter. So a barrel of oil is *exactly*
0.158987294928 m^3, and 1 m^3/sec is exactly 13.7365022817792
kbarrels/day. (Please feel free to check my math.) That's
admittedly a lot of digits, but there's no need for approximations
(unless they're imposed by the numeric representation you're using).

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Antony

unread,
Sep 28, 2010, 3:20:24 PM9/28/10
to
On 9/28/2010 9:46 AM, Ron Garret wrote:
> I have an updated version of his code that streamlines it and fixes a
> couple of bugs if anyone is interested.
>
Would you mind putting it up somewhere.

Thanks,
-Antony

Pascal J. Bourguignon

unread,
Sep 28, 2010, 3:20:52 PM9/28/10
to
George Neuner <gneu...@comcast.net> writes:

Well, I don't know how a C program can determine the type of an
argument, so how could it determine it is valid?


Technically (and this is the problem), the caller didn't have to
override anything to pass a value of the wrong type, in this case.
Granted the callee had to do something special, using varargs, to be
able to disable the type system there.

SO C typing is weak, if not inexistant (when disabled).


Compare with a dynamically, strongly typed language:


(defun sum (&rest args) ; no need for an argument count
(reduce (function +) args))

(defun main ()
(format t "~D~%" (sum 1.2 "trois" 4)))


CL-USER> (main)

*** - +: "trois" is not a number


% gcc -o sum-int sum-int.c && ./sum-int
19970680

There's also a non-null probability that the result of the sum_int
function be what is expected (in a test).

Erik Max Francis

unread,
Sep 28, 2010, 6:02:10 PM9/28/10
to

There are already numerous libraries that help you with this kind of
things in various languages; Python (you're crossposting to
comp.lang.python), for instance, has several, such as Unum, and
including one I've written but not yet released. It's not clear why one
would need this built into the language:

>>> print si
kg m s A K cd mol
>>> length = 3*si.in_ # underscore is needed since `in` is a keyword
>>> print length
3.0 in_
>>> lengthInCentimeters = length.convert(si.cm)
>>> print lengthInCentimeters
7.62 cm
>>> area = lengthInCentimeters*lengthInCentimeters
>>> print area
58.0644 cm**2
>>> biggerArea = 10.0*area
>>> ratio = area/biggerArea
>>> print ratio
0.1
>>> speed = (3.0*si.m)/(1.5*si.s)
>>> print speed
2.0 m/s
>>> ratio - speed
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "unity.py", line 218, in __sub__
converted = other.convert(self.strip())
File "unity.py", line 151, in convert
raise IncompatibleUnitsError, "%r and %r do not have compatible
units" % (self, other)
__main__.IncompatibleUnitsError: <Quantity @ 0x-4814a834 (2.0 m/s)> and
<Quantity @ 0x-4814a7d4 (1.0)> do not have compatible units

And everybody's favorite:

>>> print ((epsilon_0*mu_0)**-0.5).simplify()
299792458.011 m/s
>>> print c # floating point accuracy aside
299792458.0 m/s

--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis
In Heaven all the interesting people are missing.
-- Friedrich Nietzsche

Keith Thompson

unread,
Sep 28, 2010, 6:51:14 PM9/28/10
to
Erik Max Francis <m...@alcyone.com> writes:
[...]

> >>> print c # floating point accuracy aside
> 299792458.0 m/s

Actually, the speed of light is exactly 299792458.0 m/s by
definition. (The meter and the second are defined in terms of the
same wavelength of light; this was changed relatively recently.)

Rob Warnock

unread,
Sep 28, 2010, 7:52:11 PM9/28/10
to
EXECUTIVE SUMMARY:

1 inch + 1 second = ~4.03e38 grams.

GORY DETAILS:

Tim Bradshaw <t...@tfeb.org> wrote:
+---------------


| Malcolm McLean said:
| > he problem is that if you allow expressions rather than terms then
| > the experssions can get arbitrarily complex. sqrt(1 inch + 1 Second),
| > for instance.
|
| I can't imagine a context where 1 inch + 1 second would not be an
| error, so this is a slightly odd example. Indeed I think that in
| dimensional analysis summing (or comparing) things with different
| dimensions is always an error.

+---------------

Unless you convert them to equivalent units first. For example, in
relativistic or cosmological physics, one often uses a units basis
wherein (almost) everything is scaled to "1":

http://en.wikipedia.org/wiki/Natural_units

When you set c = 1, then:

Einstein's equation E = mc2 can be rewritten in Planck units as E = m.
This equation means "The rest-energy of a particle, measured in Planck
units of energy, equals the rest-mass of a particle, measured in
Planck units of mass."

See also:

http://en.wikipedia.org/wiki/Planck_units
...
The constants that Planck units, by definition, normalize to 1 are the:
* Gravitational constant, G;
* Reduced Planck constant, h-bar; [h/(2*pi)]
* Speed of light in a vacuum, c;
* Coulomb constant, 1/(4*pi*epsilon_0) (sometimes k_e or k);
* Boltzmann's constant, k_B (sometimes k).

This sometimes leads people to do things that would appear sloppy
or even flat-out wrong in MKS or CGS units, such as expressing mass
in terms of length:

Consider the equation A=1e10 in Planck units. If A represents a
length, then the equation means A=1.6e-25 meters. If A represents
a mass, then the equation means A=220 kilograms. ...
In fact, natural units are especially useful when this ambiguity
is *deliberate*: For example, in special relativity space and time
are so closely related that it can be useful to not specify whether
a variable represents a distance or a time.

So it is that we find that the mass of the Sun is 1.48 km or 4.93 us, see:

http://en.wikipedia.org/wiki/Solar_mass#Related_units

In this limited sense, then, one could convert both 1 inch and 1 second
to masses[1], and *then* add them, hence:

1 inch + 1 second = ~4.03e38 grams.

;-} ;-}


-Rob

[1] 1 inch is "only" ~3.41e28 g, whereas 1 second is ~4.03e38 g,
so the latter completely dominates in the sum.

-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607

George Neuner

unread,
Sep 28, 2010, 9:35:17 PM9/28/10
to
On Tue, 28 Sep 2010 12:15:07 -0700, Keith Thompson <ks...@mib.org>
wrote:

>George Neuner <gneu...@comcast.net> writes:
>> On 28 Sep 2010 12:42:40 GMT, Albert van der Horst
>> <alb...@spenarnc.xs4all.nl> wrote:
>>>I would say the dimensional checking is underrated. It must be
>>>complemented with a hard and fast rule about only using standard
>>>(SI) units internally.
>>>
>>>Oil output internal : m^3/sec
>>>Oil output printed: kbarrels/day
>>
>> "barrel" is not an SI unit.
>
>He didn't say it was. Internal calculations are done in SI units (in
>this case, m^3/sec); on output, the internal units can be converted to
>whatever is convenient.

That's true. But it is a situation where the conversion to SI units
loses precision and therefore probably shouldn't be done.

>
>> And when speaking about oil there isn't
>> even a simple conversion.
>>
>> 42 US gallons ? 34.9723 imp gal ? 158.9873 L
>>
>> [In case those marks don't render, they are meant to be the
>> double-tilda sign meaning "approximately equal".]
>
>There are multiple different kinds of "barrels", but "barrels of oil"
>are (consistently, as far as I know) defined as 42 US liquid gallons.
>A US liquid gallon is, by definition, 231 cubic inches; an inch
>is, by definition, 0.0254 meter. So a barrel of oil is *exactly*
>0.158987294928 m^3, and 1 m^3/sec is exactly 13.7365022817792
>kbarrels/day. (Please feel free to check my math.) That's
>admittedly a lot of digits, but there's no need for approximations
>(unless they're imposed by the numeric representation you're using).

I don't care to check it ... the fact that the SI unit involves 12
decimal places whereas the imperial unit involves 3 tells me the
conversion probably shouldn't be done in a program that wants
accuracy.

George

Erik Max Francis

unread,
Sep 29, 2010, 2:03:55 AM9/29/10
to
Keith Thompson wrote:
> Erik Max Francis <m...@alcyone.com> writes:
> [...]
>> >>> print c # floating point accuracy aside
>> 299792458.0 m/s
>
> Actually, the speed of light is exactly 299792458.0 m/s by
> definition. (The meter and the second are defined in terms of the
> same wavelength of light; this was changed relatively recently.)

I know. Hence why I wrote the comment "floating point accuracy aside"
when printing it.

--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 18 N 121 57 W && AIM/Y!M/Skype erikmaxfrancis

If the past sits in judgment on the present, the future will be lost.
-- Winston Churchill

Torsten Zühlsdorff

unread,
Sep 29, 2010, 5:53:17 AM9/29/10
to
Keith Thompson schrieb:

>> >>> print c # floating point accuracy aside
>> 299792458.0 m/s
>
> Actually, the speed of light is exactly 299792458.0 m/s by
> definition.

Yes, but just in vacuum.

Greetings,
Torsten
--
http://www.dddbl.de - ein Datenbank-Layer, der die Arbeit mit 8
verschiedenen Datenbanksystemen abstrahiert,
Queries von Applikationen trennt und automatisch die Query-Ergebnisse
auswerten kann.

Pascal J. Bourguignon

unread,
Sep 29, 2010, 6:40:58 AM9/29/10
to
George Neuner <gneu...@comcast.net> writes:


Because perhaps you're thinking that oil is sent over the oceans, and
sold retails in barrils of 42 gallons?

Actually, when I buy oil, it's from a pump that's graduated in liters!

It comes from trucks with citerns containing 24 mł.

And these trucks get it from reservoirs of 23,850 mł.

"Tankers move approximately 2,000,000,000 metric tons" says the English
Wikipedia page...

Now perhaps it all depends on whether you buy your oil from Total or
from Texaco, but in my opinion, you're forgetting something: the last
drop. You never get exactly 42 gallons of oil, there's always a little
drop more or less, so what you get is perhaps 158.987 liter or
41.9999221 US gallons, or even 158.98 liter = 41.9980729 US gallons,
where you need more significant digits.

Tim Bradshaw

unread,
Sep 29, 2010, 7:42:54 AM9/29/10
to
On 2010-09-29 00:52:11 +0100, Rob Warnock said:

> Unless you convert them to equivalent units first. For example, in
> relativistic or cosmological physics, one often uses a units basis
> wherein (almost) everything is scaled to "1":

Heh. I spent a bunch of time doing GR so I'm used to these. Although
natural units are obviously convenient for doing calculations, I often
found that when I was getting answers that were obviously nonsensical
putting in the units would find dimansion errors I'd made.

Paul Wallich

unread,
Sep 29, 2010, 8:55:57 AM9/29/10
to
[...]

>
> Now perhaps it all depends on whether you buy your oil from Total or
> from Texaco, but in my opinion, you're forgetting something: the last
> drop. You never get exactly 42 gallons of oil, there's always a little
> drop more or less, so what you get is perhaps 158.987 liter or
> 41.9999221 US gallons, or even 158.98 liter = 41.9980729 US gallons,
> where you need more significant digits.

And even that pales in comparison to the expansion and contraction of
petroleum products with temperature. Compensation to standard temp is
required in some jurisdictions but not in others...

Keith Thompson

unread,
Sep 29, 2010, 10:00:56 AM9/29/10
to
Erik Max Francis <m...@alcyone.com> writes:
> Keith Thompson wrote:
>> Erik Max Francis <m...@alcyone.com> writes:
>> [...]
>>> >>> print c # floating point accuracy aside
>>> 299792458.0 m/s
>>
>> Actually, the speed of light is exactly 299792458.0 m/s by
>> definition. (The meter and the second are defined in terms of the
>> same wavelength of light; this was changed relatively recently.)
>
> I know. Hence why I wrote the comment "floating point accuracy aside"
> when printing it.

Ok. I took the comment to be an indication that the figure was
subject to floating point accuracy concerns; in fact you meant just
the opposite.

Thomas A. Russ

unread,
Sep 29, 2010, 1:54:53 PM9/29/10
to
George Neuner <gneu...@comcast.net> writes:

> On Tue, 28 Sep 2010 12:15:07 -0700, Keith Thompson <ks...@mib.org>
> wrote:
> >He didn't say it was. Internal calculations are done in SI units (in
> >this case, m^3/sec); on output, the internal units can be converted to
> >whatever is convenient.
>
> That's true. But it is a situation where the conversion to SI units
> loses precision and therefore probably shouldn't be done.

I suppose that one has to choose between two fundamental designs for any
computational system of units. One can either store the results
internally in a canonical form, which generally means an internal
representation in SI units. Then all calculations are performed using
the interal units representation and conversion happens only on input or
output.

Or one can store the values in their original input form, and perform
conversions on the fly during calculations. For calculations one will
still need to have some canonical representation for cases where the
result value doesn't have a preferred unit provided. For internal
calculations this will often be the case.

Now whether one will necessarily have a loss of precision depends on
whether the conversion factors are exact or approximations. As long as
the factors are exact, one can have the internal representation be exact
as well. One method would be to use something like the Commmon Lisp
rational numbers or the Gnu mp library.

And a representation where one preserves the "preferred" unit for
display purposes based on the original data as entered is also nice.
Roman Cunis' Common Lisp library does that, and with the use of rational
numbers for storing values and conversion factors allows one to do nice
things like make sure that

30mph * 3h = 90mi

even when the internal representation is in SI units (m/s, s, m).

George Neuner

unread,
Sep 29, 2010, 2:18:27 PM9/29/10
to


No. I'm just reacting to the "significant figures" issue. Real
world issues like US vs Eurozone and measurement error aside - and
without implying anyone here - many people seem to forget that
multiplying significant figures doesn't add them, and results to 12
decimal places are not necessarily any more accurate than results to 2
decimal places.

It makes sense to break macro barrel into micro units only when
necessary. When a refinery purchases 500,000 barrels, it is charged a
barrel price, not some multiple of gallon or liter price and
regardless of drop over/under. The refinery's process is continuous
and it needs a delivery if it has less than 20,000 barrels - so the
current reserve figure of 174,092 barrels is as accurate as is needed
(they need to order by tomorrow because delivery will take 10 days).
OTOH, because the refinery sells product to commercial vendors of
gasoline/petrol and heating oil in gallons or liters, it does makes
sense to track inventory and sales in (large multiples of) those
units.

Similarly, converting everything to mł simply because you can does not
make sense. When talking about the natural gas reserve of the United
States, the figures are given in Kmł - a few thousand mł either way is
irrelevant.

George

Squeamizh

unread,
Sep 29, 2010, 3:41:00 PM9/29/10