[comp.lang.c] more on TRUE and FALSE

rtm@christmas.UUCP (Richard Minner) (09/15/90)

This whole discussion of #defining TRUE and FALSE reminded me
of one of my favorite fortunes of all time:

  The primary purpose of the DATA statement is to give names to
  constants; instead of referring to pi as 3.141592653589793 at every
  appearance, the variable PI can be given that value with a DATA
  statement and used instead of the longer form of the constant.  This
  also simplifies modifying the program, should the value of pi change.
		-- FORTRAN manual for Xerox Computers

I've read it a dozen times or more and it still makes me laugh.

Personally, I like to use:

#define 0	0
#define 1	1

Just to be sure...

Actually, I use TRUE and FALSE, but only for assignments and return
values, honest. ;-)

The construct:
	if (boolvar == TRUE)
is just plain silly, even in pascal where it's `safe'.  Get real.
(And the `what about novice programmers' argument is specious;
a novice programmer might do anything.  Besides, I'd bet a novice
would be at least as likely to screw up code that uses `flag = 1'
and `return 1'.)

Gee, if you want to be really really clear, why not use:

#define TRUE		1
#define REALLY_TRUE	1
#define TRUE_AS_CAN_BE	1
#define FALSE		0
#define REALLY_FALSE	0
#define EVER_SO_FALSE	0

    if (((boolvar == TRUE) == REALLY_TRUE) == TRUE_AS_CAN_BE)
	...

On a more serious note, one drawback of not having a real
boolean type is that you can't blithely go
	if (boolvar1 == boolvar2)
to mean
	if ((boolvar1 && boolvar2) || (!boolvar1 && !boolvar2))
which is a (small) shame.

Something I'd like to see more of is the `boolify' operator: !!
I've almost written `if (!!boolvar1 == !!boolvar2)' on occasion
but I was afraid it might be too strange.  However, I have used
`boolvar = !!intvar' at times (mainly as a reminder to myself).
(I also worry that a broken compiler might erroneously toss out
!!'s, similar to the &&&*** bug discussed.)

For those who still don't like TRUE and FALSE, you might consider
using `1/*true*/' and `0/*false*/' (you could even bind them to
editor macros, golly), as in:
	is_so   = 1/*true*/;
	aint_so = 0/*false*/;
	return 1/*true*/;
Ugly but clear.  I tried it for a while, and still use it sometimes
when TRUE and FALSE aren't around.  More to the point, it's good
practice to give boolean variables and functions `predicate' names,
e.g. use `is_init' instead of just `init', and is_valid(thing)
instead of check(thing).  (But then there are the is*() ctype
functions that return arbitrary non-0 values for true.  Oh well,
I guess it's still C...)

-- 
Richard Minner  || {uunet,sun,well}!island!rtm     (916) 736-1323 ||
                || Island Graphics Corporation     Sacramento, CA ||

ergo@netcom.UUCP (Isaac Rabinovitch) (09/17/90)

In <9@christmas.UUCP> rtm@christmas.UUCP (Richard Minner) writes:


>  The primary purpose of the DATA statement is to give names to
>  constants; instead of referring to pi as 3.141592653589793 at every
>  appearance, the variable PI can be given that value with a DATA
>  statement and used instead of the longer form of the constant.  This
>  also simplifies modifying the program, should the value of pi change.
>		-- FORTRAN manual for Xerox Computers

That reminds me of something I spotted shortly after ATT started
getting commercial with Unix.  Apparently they hired a lot of English
majors to clean up the man pages.  One of them spotted a reference to
"atomic" transactions (meaning an IPC transaction that couldn't be
borken down further); apparently s/he said, "No, that can't be right,"
and changed it to "automatic".  

>(And the `what about novice programmers' argument is specious;
>a novice programmer might do anything.  Besides, I'd bet a novice
>would be at least as likely to screw up code that uses `flag = 1'
>and `return 1'.)

Who was it that said, "No system is foolproof -- fools are extremely
clever people"?
-- 

ergo@netcom.uucp			Isaac Rabinovitch
{apple,amdahl,claris}!netcom!ergo	Silicon Valley, CA

Collins's Law:
	If you can't make a mistake, you can't make anything.

Corollaries ("Rabinovitch's Rules of Sane Dialogue"):
	1. Everybody who matters is stupid now and then.
	2. If I'm being stupid, that's my problem.
	3. If my being stupid makes you stupid, that's your problem.
	4. If you think you're never stupid, boy are you stupid!

quan@sol.surv.utas.oz (Stephen Quan) (09/17/90)

Personally I hate 'writing' programs with :

  if (strcmp(name,"hippo")==0) ....

I know 'strcmp(a,b)' is designed to return 3 types of value :
-ve : a comes before b.
  0 : a equals b.
+ve : a comes after b.

but it drives me balmy (not completely balmy though!) all the same.

Anyone got a cure?  At the moment I'm trying DIET COKE!

Stephen Quan (quan@sol.surv.utas.edu.au - ignore oz.au above, if it appears)
Programmer (won't admit which compiler I have to use, but it starts with F),
University of Tasmania,
Aussie.

brad@SSD.CSD.HARRIS.COM (Brad Appleton) (09/17/90)

In article <quan.653570879@sol> quan@sol.surv.utas.oz (Stephen Quan) writes:
>Personally I hate 'writing' programs with :
>
>  if (strcmp(name,"hippo")==0) ....
>
>I know 'strcmp(a,b)' is designed to return 3 types of value :
>-ve : a comes before b.
>  0 : a equals b.
>+ve : a comes after b.
>
>but it drives me balmy (not completely balmy though!) all the same.
>
>Anyone got a cure?  At the moment I'm trying DIET COKE!

It may not be terribly readable, but i use:

	if ( !strcmp(s1, s2) )  { ... }

To test for equality!!

Ive also seen (but dont use) the following:

#define  strEQ(s1,s2)  !strcmp(s1,s2)
#define  strNE(s1,s2)  strcmp(s1,s2)
#define  strLT(s1,s2)  ( strcmp(s1,s2) < 0 )
#define  strGT(s1,s2)  ( strcmp(s1,s2) > 0 )

(and similar stuff for strncmp too!)

______________________ "And miles to go before I sleep." ______________________
 Brad Appleton        brad@travis.ssd.csd.harris.com   Harris Computer Systems
                          ...!uunet!hcx1!brad          Fort Lauderdale, FL USA
~~~~~~~~~~~~~~~~~~~~ Disclaimer: I said it, not my company! ~~~~~~~~~~~~~~~~~~~

jh4o+@andrew.cmu.edu (Jeffrey T. Hutzelman) (09/17/90)

Try

if (!strcmp(name,"hippo"))

It works, although it's a bit confusing to those who don't know that
strcmp() returns 0 for equal and non-0 for unequal.

Or, write a macro:

#define strequ(a,b) !strcmp(a,b)
if (strequ(name,hippo))
-----------------
Jeffrey Hutzelman
America Online: JeffreyH11
Internet/BITNET:jh4o+@andrew.cmu.edu, jhutz@drycas.club.cc.cmu.edu

>> Apple // Forever!!! <<

manning@gap.caltech.edu (Evan Marshall Manning) (09/17/90)

quan@sol.surv.utas.oz (Stephen Quan) writes:

>Personally I hate 'writing' programs with :

>  if (strcmp(name,"hippo")==0) ....

>but it drives me balmy (not completely balmy though!) all the same.

>Anyone got a cure?  At the moment I'm trying DIET COKE!

Try caffeine-free diet Coke.

I use:

#define	STRING_MATCH	0	/* strcmp() returns 0 if strings match */

  if (strcmp(name,"potamus") == STRING_MATCH) ....

***************************************************************************
Your eyes are weary from staring at the CRT for so | Evan M. Manning
long.  You feel sleepy.  Notice how restful it is  |      is
to watch the cursor blink.  Close your eyes.  The  |manning@gap.cco.caltech.edu
opinions stated above are yours.  You cannot       | manning@mars.jpl.nasa.gov
imagine why you ever felt otherwise.               | gleeper@tybalt.caltech.edu

flee@dictionopolis.cs.psu.edu (Felix Lee) (09/18/90)

>Personally I hate 'writing' programs with :
>  if (strcmp(name,"hippo")==0) ....

Try writing this instead:
	IF(strcmp(name, "hippo"), L10, L20, L10)
  L10:	printf("%s is not a hippo\n", name);
	GOTO(L30)
  L20:  printf("a hippo\n");
	GOTO(L30)
  L30:	CONTINUE

And here are the macros that make it possible:

#define IF(e,a,b,c) {int _=(e);if(_<0)GOTO(a)else if(_>0)GOTO(c)else GOTO(b)}
#define GOTO(x) goto x;
#define CONTINUE ;

Exercise for the reader:
* The printf statements are ugly.  Define FORMAT and WRITE statements.
You will probably need functions (in addition to/instead of) macros.
--
Felix Lee	flee@cs.psu.edu

bean@putter.wpd.sgi.com (Bean Anderson) (09/18/90)

In article <9@christmas.UUCP>, rtm@christmas.UUCP (Richard Minner) writes:
|> 
|> This whole discussion of #defining TRUE and FALSE reminded me
|> of one of my favorite fortunes of all time:
|> 
|>   The primary purpose of the DATA statement is to give names to
|>   constants; instead of referring to pi as 3.141592653589793 at every
|>   appearance, the variable PI can be given that value with a DATA
|>   statement and used instead of the longer form of the constant.  This
|>   also simplifies modifying the program, should the value of pi change.
|> 		-- FORTRAN manual for Xerox Computers
|> 
|> I've read it a dozen times or more and it still makes me laugh.
|> 
|

I too laughed at this and then, feeling charitable, realized it was 
possible that the author had more insight than we have given him/her
credit.  

You see, we often forget that floating point numbers are *not* 
REAL numbers, in the mathematical meaning of REAL numbers; they
are, at best, a gross approximation.  Therefore, while the value
of pi will never change, the representation of it can easily 
change from machine to machine depending upon the degree of
accuracy available.  

I kind of doubt this was the author's concern; but I had a nice
weekend, the sun was out in San Francisco, I got paid when a lot
of people in other companies are being laid off, and no
disasters were waiting for me this Monday morning.....


			Bean

mcdaniel@adi.com (Tim McDaniel) (09/18/90)

In article <9@christmas.UUCP> rtm@christmas.UUCP (Richard Minner)
writes:

   More to the point, it's good
   practice to give boolean variables and functions `predicate' names,
   e.g. use `is_init' instead of just `init', and is_valid(thing)
   instead of check(thing).

Excellent.  A warning to the unStandardified: external names beginning
with "is" or "to", followed by a lowercase letter, followed by
any identifier characters, is reserved in the Standard if you include
<ctype.h>.  'is_init' or 'isInit' is portable; 'isinit' is not.
--
Tim McDaniel                 Applied Dynamics Int'l.; Ann Arbor, Michigan, USA
Work phone: +313 973 1300                            Home phone: +313 677 4386
Internet: mcdaniel@adi.com                UUCP: {uunet,sharkey}!amara!mcdaniel

henry@zoo.toronto.edu (Henry Spencer) (09/18/90)

In article <quan.653570879@sol> quan@sol.surv.utas.oz (Stephen Quan) writes:
>Personally I hate 'writing' programs with :
>
>  if (strcmp(name,"hippo")==0) ....

Agreed.  This is a *very* confusing convention, made all the worse by
pinheads who shorten it to `if (strcmp(a, b))' or `if (!strcmp(a, b))'
without considering what a nuisance this is to readers.  Our local
custom is to define a STREQ macro; the inequality comparisons are much
less troublesome (and much rarer) and don't really need the help.  My
current favorite definition is:

#define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)

Note that this is an unsafe macro; on the other hand, it is typically
much faster than one which just calls strcmp every time.  Most string
comparisons fail on the first character.
-- 
TCP/IP: handling tomorrow's loads today| Henry Spencer at U of Toronto Zoology
OSI: handling yesterday's loads someday|  henry@zoo.toronto.edu   utzoo!henry

flaps@dgp.toronto.edu (Alan J Rosenthal) (09/19/90)

flee@dictionopolis.cs.psu.edu (Felix Lee) writes:
>Try writing this instead:
>	IF(strcmp(name, "hippo"), L10, L20, L10)
>  L10:	printf("%s is not a hippo\n", name);
>	GOTO(L30)
...
>And here are the macros that make it possible:

Try writing this instead (syntax subject to minor slips of memory):

	if (name(1) .eq. 1hh
	1	.and. name(2) .eq. 1hi
	2	.and. name(3) .eq. 1hp
	3	.and. name(4) .eq. 1hp
	4	.and. name(5) .eq. 1ho) 10, 20, 10
10	write (6,11),name
11	format (1x, a, 15h is not a hippo)
	goto 30

And here is the shellscript that makes it possible:

	f77 "$@"

userAKDU@mts.ucs.UAlberta.CA (Al Dunbar) (09/20/90)

In article <1990Sep19.114448.22151@jarvis.csri.toronto.edu>, flaps@dgp.toronto.edu (Alan J Rosenthal) writes:
>flee@dictionopolis.cs.psu.edu (Felix Lee) writes:
>>Try writing this instead:
>>       IF(strcmp(name, "hippo"), L10, L20, L10)
>>  L10: printf("%s is not a hippo\n", name);
>>       GOTO(L30)
>...
>>And here are the macros that make it possible:
>
>Try writing this instead (syntax subject to minor slips of memory):
>
>        if (name(1) .eq. 1hh
>        1       .and. name(2) .eq. 1hi
>        2       .and. name(3) .eq. 1hp
>        3       .and. name(4) .eq. 1hp
>        4       .and. name(5) .eq. 1ho) 10, 20, 10
>10      write (6,11),name
>11      format (1x, a, 15h is not a hippo)
>        goto 30
>
>And here is the shellscript that makes it possible:
>
>        f77 "$@"
 
Actually, another factor which makes the above possible is the
insistence of many Fortran programmers (it must have been a
*long* time since you were one) to use the patently obsolete
features of the (pre-77) language, such as: arithmetic goto's,
hollerith constants, and storing character strings unpacked in
integer arrays.
 
-------------------+-------------------------------------------
Al Dunbar          |
Edmonton, Alberta  |   this space for rent
CANADA             |
-------------------+-------------------------------------------

scjones@thor.UUCP (Larry Jones) (09/20/90)

In article <1990Sep18.163533.16008@zoo.toronto.edu>, henry@zoo.toronto.edu (Henry Spencer) writes:
> My current favorite definition is:
> 
> #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
> 
> Note that this is an unsafe macro; on the other hand, it is typically
> much faster than one which just calls strcmp every time.  Most string
> comparisons fail on the first character.

And it's slower than one that just calls strcmp every time if your
compiler is smart enough to generate in-line code for strcmp!

Of course, the beauty of a macro is that you can change it without
having to change all the code that uses it.
----
Larry Jones                         UUCP: uunet!sdrc!thor!scjones
SDRC                                      scjones@thor.UUCP
2000 Eastman Dr.                    BIX:  ltl
Milford, OH  45150-2789             AT&T: (513) 576-2070
Nobody knows how to pamper like a Mom. -- Calvin

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (09/21/90)

In article <181@thor.UUCP> scjones@thor.UUCP (Larry Jones) writes:
> In article <1990Sep18.163533.16008@zoo.toronto.edu>, henry@zoo.toronto.edu (Henry Spencer) writes:
> > My current favorite definition is:
> > #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
> And it's slower than one that just calls strcmp every time if your
> compiler is smart enough to generate in-line code for strcmp!

Which is why it should be

#define STREQ(a,b)  ( *(a) == *(b) && *(a) && !strcmp((a)+1, (b)+1) )

instead.

Probably calling strcmp ``strdiff'' will answer the original question.
``if (strdiff(a,b))'' makes sense, right?

---Dan

karl@haddock.ima.isc.com (Karl Heuer) (09/22/90)

In article <14084:Sep2105:38:0890@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>#define STREQ(a,b)  ( *(a) == *(b) && *(a) && !strcmp((a)+1, (b)+1) )

Nope.  Try
#define STREQ(a,b)  ( *(a) == *(b) && (*(a)=='\0' || strcmp((a)+1, (b)+1)==0) )

(or the equivalent but muddier construct:)
#define STREQ(a,b)  ( *(a) == *(b) && !(*(a) && strcmp((a)+1, (b)+1)) )

Or just use the original macro, but conditionalize it on HAVE_INLINE_STRCMP.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (09/22/90)

In article <18097@haddock.ima.isc.com> karl@kelp.ima.isc.com (Karl Heuer) writes:
> In article <14084:Sep2105:38:0890@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
   [ incorrectly ]
> >#define STREQ(a,b)  ( *(a) == *(b) && *(a) && !strcmp((a)+1, (b)+1) )
> #define STREQ(a,b)  ( *(a) == *(b) && !(*(a) && strcmp((a)+1, (b)+1)) )

Yes, you're right. Sorry. Thanks also to Peter Montgomery for pointing
this out. In any case it's better than the original macro, whether
strcmp is inlined or not.

---Dan

henry@zoo.toronto.edu (Henry Spencer) (09/23/90)

In article <18292:Sep2203:27:3090@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>> #define STREQ(a,b)  ( *(a) == *(b) && !(*(a) && strcmp((a)+1, (b)+1)) )
>
>Yes, you're right. Sorry. Thanks also to Peter Montgomery for pointing
>this out. In any case it's better than the original macro, whether
>strcmp is inlined or not.

Nope, sorry, not clearly so.  We're not stupid; we thought of that.  The
question is whether doing a redundant test of the initial byte within
strcmp is really slower than the `*(a)' test plus two pointer increments.
Our conclusion was that it usually isn't... particularly if you have a
clever strcmp that does compares a word at a time, in which case you're
quite possibly fouling it up by ruining the alignment of the operands.
It certainly isn't a clear win, so the extra complexity is unjustified.
-- 
TCP/IP: handling tomorrow's loads today| Henry Spencer at U of Toronto Zoology
OSI: handling yesterday's loads someday|  henry@zoo.toronto.edu   utzoo!henry

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (09/26/90)

#define STRCMP(a,op,b)	(strcmp(a,b) op 0)

     if (STRCMP(a, ==, b))
          (void) printf("a == b\n");
     if (STRCMP(c, <, d))
        (void) printf("c < d\n");
--
Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com>
UUCP:  oliveb!cirrusl!dhesi

weiske@lan.informatik.tu-muenchen.dbp.de (Thomas Weiske) (09/28/90)

I use some very useful header files because I cant remember
the actual encoding of TRUE/FALSE. Actually I cant remember
the correct writing of True or False, sometimes I prefer
true and false depending on the context to get a nice C 
Program Layout.
Here is the first one:
---x---x---x---x---x---x---x---x---x---x---
#define TRUE	((0)==(0))
#define True	TRUE
#define true	True
#define FALSE	((1)==(2))
#define False	FALSE
#define false	False
---x---x---x---x---x---x---x---x---x---x---
To make the definitions more tolerant to typos
you can add
'Treu' or 'Fasle' a.s.o.
The interesting thing is the compatibility to
all in this newsgroup suggested encodings of 
TRUE and FALSE without any loss of runtime speed!

I also use many loops in my programs, but I dont like
while(1), while(TRUE) or for(;;).
This looks ugly and does not express the real meaning
of the loop.
I prefer:
---x---x---x---x---x---x---x---x---x---x---
#define ever	(;;)
---x---x---x---x---x---x---x---x---x---x---
Now you can write:
	for ever {Stuff}
I like it much more than 'forever' and the header
file is 6 Bytes shorter!

Now here is my solution to the self printing C program:
---x---x---x---x---x---x---x---x---x---x---
#include <stdio.h>
main(){
  int c; FILE *f=fopen(__FILE__,"r");
  while(f&&(c=getc(f))!=EOF)putchar(c);
}
---x---x---x---x---x---x---x---x---x---x---

--
Thomas Weiske                        | Phone +89/2105 8136
weiske@lan.informatik.tu-muenchen.de | Fax   +89/2105 8180
Technische Universit"at M"unchen

karl@haddock.ima.isc.com (Karl Heuer) (09/29/90)

In article <4673@tuminfo1.lan.informatik.tu-muenchen.dbp.de> weiske@lan.informatik.tu-muenchen.dbp.de (Thomas Weiske) writes:
>[A whole bunch of SLMs]

I'm going to assume this was a joke, because I don't have the time to deal
with anything this silly if it's serious.%

>To make the definitions more tolerant to typos you can add
>'Treu' or 'Fasle' a.s.o.

I'm reminded of a note in a Fortran manual: if you find you've already punched
your program and misspelled the variable CHIEF as CHEIF on a lot of the cards,
you can fix it with EQUIVALENCE(CHEIF,CHIEF).

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint
________
% If you thought it was "obviously" a joke, you haven't been reading the group
  long enough to see all the crap that people seriously propose.  This is why
  emoticons are useful.

lerman@stpstn.UUCP (Ken Lerman) (09/29/90)

In article <18306@haddock.ima.isc.com> karl@kelp.ima.isc.com (Karl Heuer) writes:
[...]
->
->I'm reminded of a note in a Fortran manual: if you find you've already punched
->your program and misspelled the variable CHIEF as CHEIF on a lot of the cards,
->you can fix it with EQUIVALENCE(CHEIF,CHIEF).
->
->Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint
->________
[...]

Ugh, a ghastly solution.  The right way is to get some scotch (brand)
tape and some punchings and tape the "bits" back in the holes.  (You
may laugh, but I've seen people actually do this.  With binary
(encoded) cards, no less.)

Ken

userAKDU@mts.ucs.UAlberta.CA (Al Dunbar) (09/29/90)

In article <4673@tuminfo1.lan.informatik.tu-muenchen.dbp.de>, weiske@lan.informatik.tu-muenchen.dbp.de (Thomas Weiske) writes:
>I use some very useful header files because I cant remember
>the actual encoding of TRUE/FALSE. Actually I cant remember
>the correct writing of True or False, sometimes I prefer
>true and false depending on the context to get a nice C
>Program Layout.
>Here is the first one:
>---x---x---x---x---x---x---x---x---x---x---
>#define TRUE    ((0)==(0))
>#define True    TRUE
>#define true    True
>#define FALSE   ((1)==(2))
>#define False   FALSE
>#define false   False
>---x---x---x---x---x---x---x---x---x---x---
>To make the definitions more tolerant to typos
>you can add
>'Treu' or 'Fasle' a.s.o.
>The interesting thing is the compatibility to
>all in this newsgroup suggested encodings of
>TRUE and FALSE without any loss of runtime speed!
>
an interesting concept! You could also define FOUR, FORE, and
FOYER (in various combinations of upper/lower case) as 'for',
just in case one day you forgot how to spell 'for'. That would
certainly give you a nice "program layout".
 
-------------------+-------------------------------------------
Al Dunbar          |
Edmonton, Alberta  |   this space for rent
CANADA             |
-------------------+-------------------------------------------
#! r

rh@smds.UUCP (Richard Harter) (09/30/90)

In article <5625@stpstn.UUCP>, lerman@stpstn.UUCP (Ken Lerman) writes:

> Ugh, a ghastly solution.  The right way is to get some scotch (brand)
> tape and some punchings and tape the "bits" back in the holes.  (You
> may laugh, but I've seen people actually do this.  With binary
> (encoded) cards, no less.)

No, no, no, a thousand times no.  Scotch tape comes off and sticks in
the card reader.  Just put the chad (not bits) back in the holes and
smooth them down with a fingernail.  The "repaired" cards will last
indefinitely.

We now return to the 1990's.
-- 
Richard Harter, Software Maintenance and Development Systems, Inc.
Net address: jjmhome!smds!rh Phone: 508-369-7398 
US Mail: SMDS Inc., PO Box 555, Concord MA 01742
This sentence no verb.  This sentence short.  This signature done.