Re: OT: Language War (Re: "C" Manual)

2002-01-16 Thread Craig Dickson
Richard Cobbe wrote:

> C:
> int x;
> 
> x = "foo";
> 
> You'll get a type error here at compile time, for obvious reasons.
> Question: how can this be a type error if only variables have types?
> You need to realize that "foo" has type (const) char * before you can
> determine that you can't assign it to an int.

"foo" isn't a pointer to char (char*); it's an array of char (char[]).
Consider:

int main()
{
char* p = "foobar";

printf("sizeof pointer = %d\n", sizeof(p));
printf("sizeof array   = %d\n", sizeof("foobar"));

return 0;
}

This produces the following output:

sizeof pointer = 4
sizeof array   = 7

(The array has size 7 because the string literal automatically gets a
null appended to its six elements.)

This is a nitpicky point, and not one which invalidates the rest of your
argument, but it is a common error of novice C programmers not to
understand the difference between arrays and pointers (which the
language makes confusing by passing arrays by reference and allowing the
array-index operator to be applied to pointers), so when this sort of
thing pops up, I like to point it out.

Craig


pgpaUmL34K0nP.pgp
Description: PGP signature


Re: OT: Language War (Re: "C" Manual)

2002-01-16 Thread Richard Cobbe
Lo, on Sunday, January 13, Erik Steffl did write:

>   type is a propert of variable.

Not exclusively.  Two counter-examples, one in C, and one in Scheme.

C:
int x;

x = "foo";

You'll get a type error here at compile time, for obvious reasons.
Question: how can this be a type error if only variables have types?
You need to realize that "foo" has type (const) char * before you can
determine that you can't assign it to an int.

Scheme:

(define f
  (lambda (x)
(cond
  ((boolean? x) (if x 42 23))
  ((symbol? x) (string-length (symbol->string x)))
  ((char? x) (char->integer x))
  ((vector? x) (vector-length x))
  ((procedure? x) (x 42))
  ((list? x) (length x))
  ((pair? x) (car x))
  ((number? x) (- x))
  ((string? x) (string-length x))
  ((port? x) (read x))
  ((promise? x) (force x)

This defines a function f with one argument, x.  What's x's type?  The
function is equally well-defined for an argument of just about any value
supported by R5RS, the current spec.  (For that matter, what's the
return type of f?  Answer: it's usually a number, but it depends on x!)

In languages like Scheme, Lisp, Python, and Smalltalk, almost all
typechecking is deferred to run-time.  Therefore, it is meaningless to
describe the type of a variable; in these languages, types only apply to
values.

Richard



Re: OT: Language War (Re: "C" Manual)

2002-01-13 Thread Erik Steffl
dman wrote:
> 
> On Sun, Jan 06, 2002 at 04:51:14PM -0800, Erik Steffl wrote:
> | dman wrote:
> | >
> | > On Sat, Jan 05, 2002 at 09:38:01PM -0800, Erik Steffl wrote:
> | > | dman wrote:
> | > ...
> | > | > In C/C++ there is an invariant on strings ("char*", which is
> | > | > essentially equivalent to "char[]") that they end with a NUL byte.
> | > |
> | > |   no, that's not true.
> | >
> | > It is true.  A type is more than the name a compiler gives it.  A type
> |
> | the type in C is only what type in C is. what the type is in your head
> | is irrelevant.
> 
> No, a type is a certain thing, irrespective of the language you are
> currently working with.  A type is a higher-level thing than a
> compiler is.  Each languge has its own way of (trying) to express

  well, but it certainly doesn't make sense to complain about type error
when it refers to a type that's in your head only (which was at the
beginning of this thread).

...
> |   solely on name: not sure what you mean here, you refer to types by
> | names in all languages,
> 
> In python you only refer to a type by referencing a factory for that
> type (class objects are factories for their own instances).  Eg the

  what's the difference? there might be static or dynamic typing but you
still refer to it by its name (of class, factory or whatever the given
language chooses). or you just have it as a 'no-type' variable (which
basically means it's a default language type, it's basically a
shortcut).

> function you have below would be written as :
> 
> def operator_star( i , j ) :
> if i < j : segfault()
> else : return float( i*j )
> 
> note that there is no mention of the types of i, j, or the return
> value.  The closest it comes is calling a function named 'float' that

  good. that makes it even more clear that the segfault is because of
the value, not because of the type:-)

> converts it's argument to a floating point object.
> 
> | it's just that definition of type might be more
> | complicated, in C you have certain primitive types that you can use to
> | construct new type given specific operations (typedef, struct, ...), in
> | some languages you might have a way to specify type using 'procedural'
> | conditions.
> 
> 'typedef' in C is the same as #define, except for the binding of, eg,

  well, it's not a true type, you're right that it's basically a
shorthand even though a little bit different from define...

...
> 'struct' creates a name that refers to a combination of other names,
> but still that is not the complete type.

  it's really hard to tell what is a 'complete type'. the point is that
there are various ways to create a new type as various combinations of
old type (typedef being the most simple one, struct being somewhat more
complicated). in other languages you have more complex ways to specify
type (e.g. classes in OO languages).

> |   in the example above (sort of, it's not quoted anymore) there is only
> | one variable involved and so you can try to make it an issue of type,
> | why is it wrong and why you have to consider types and domains of valid
> | values separately is clear when using more than one variable.
> |
> |   imagine that you have a binary operator that only works for certain
> | values of parameters:
> 
> Ok :
> 
> | int operator * (int i, int j)
> | {
> |   if(i |   elsereturn (double)i * (double)j;
> | }
> 
> The complete type of 'j' is _not_ int.  The complete type is an
> integer that is less than i.

  the type is related to variable, not to a set of variables. show me a
way to define i (before definition of the function) so that it will be
proper type for function (function does not segfault. maybe this will
make it a bit more clear:

  Type i;

  int operator *(Type i)
  {
int j = rand();
if(i |   is there any way to specify types of i and j so that it never
> | segfaults? no.
> 
> I agree that C has no way of expressing that, which is why you need to

  C or any other language - type and set of valid values are NOT the
same thing. e.g. you have to specify type of variable when you create it
but the whether it's in the set of valid values might not be known until
it's inside of the function.

> manually insert runtime checks on the values.  You are asserting an
> invariant on the real type of 'j' since the C compiler can't do it for
> you.

  nobody can do it because outside of the function there might be no j!

> VMD-SL is a modelling language heavily based in discrete mathematics
> and logic.  In VDM-SL you create a type by beginning with a name and
> equating it to a built-in type (eg 'int', 'real', or 'token'[1]).
> Then you list all of the invariants that your new type has.  It is a
> formal language, but it is not programming, thus it is possible to
> completely specify the types.
> 
> | in general you have to consider the values separately from type. and
> | IMO it makes perfect sense in case of 'string' in C - it's just a
> | special value (special for certain functions, N

Re: OT: Language War (Re: "C" Manual)

2002-01-09 Thread dman
On Mon, Jan 07, 2002 at 03:56:45PM -0600, Richard Cobbe wrote:
| Lo, on Monday, January 7, dman did write:
 
| > Have you read "The Hobbit"?  Do you remember what Treebeard told Bilbo
| > about his name?
| 
| (Actually it was _The Two Towers_, and it was Merry & Pippin, not Bilbo,

Oops.  It's been a long time since I read them.  I'm starting The
Fellowship of the Ring again and saw the movie twice.  Good movie, but
too short!  Read the book, you'll see why.  As I was watching the
movie I kept trying to remember if it was Bilbo or Frodo who met Tom
Bombadil.  Frodo and friends just got to Tom's house where I'm at in
the book now.

| but it's still a good analogy.  )

Thanks.

-D

-- 

Contrary to popular belief, Unix is user friendly.
It just happens to be selective about who it makes friends with.
   -- Dave Parnas



Re: OT: Language War (Re: "C" Manual)

2002-01-07 Thread Erik Steffl
"Eric G. Miller" wrote:
...
> > merely a subset of them (0<=i > programming languages don't provide a mechanism to express this so
> > programmers approximate it with types that describe supersets of the
> > set they want.  (this explains why I dislike java and its type system
> > so much; for C it is acceptable because C excels at the low-level
> > problems it was intended to solve)
> 
> FYI:  There are modern languages where you can define limimited range
> numerical types.  Ada is one such language:
> 
>type Tri_State is range 0 .. 2;
> 
>or
> 
>subtype Tri_State is Integer range 0 .. 2;

  doesn't pascal allow the same type definition?

  and btw you have enum in C (well, it's only for integers and good luck
defining 0 .. 100 :-))

erik



Re: OT: Language War (Re: "C" Manual)

2002-01-07 Thread Eric G . Miller
On Mon, 7 Jan 2002 11:27:10 -0500, dman <[EMAIL PROTECTED]> wrote:

[snip]
> When you say that, in C, something is an 'int', is it possible to have
> a bit pattern there that is not a valid 'int'?  No.  'int' describes
> the set of all valid values and every possible bit pattern you can
> stick there is a valid int.  In many cases when you write 'int' in
> your code (for example the java.util.Vector.getElement() method) you
> don't really want all the valid values that 'int' describes, but
> merely a subset of them (0<=i programming languages don't provide a mechanism to express this so
> programmers approximate it with types that describe supersets of the
> set they want.  (this explains why I dislike java and its type system
> so much; for C it is acceptable because C excels at the low-level
> problems it was intended to solve)

FYI:  There are modern languages where you can define limimited range
numerical types.  Ada is one such language:

   type Tri_State is range 0 .. 2;

   or

   subtype Tri_State is Integer range 0 .. 2;


-- 
Eric G. Miller 



Re: OT: Language War (Re: "C" Manual)

2002-01-07 Thread Richard Cobbe
Lo, on Monday, January 7, dman did write:

> I've just come up with a good description of what a 'type' is :
> A "type" is the set of all valid values.

*DING*DING*DING*DING*DING*DING*

Got it in one.  Types are sets of values.  That's all.  C, C++, and Java
provide a fairly limited language for describing these values, but types
are sets of values.  (I'm using, and I suspect dman is as well, `set' in
the mathematical sense as an unordered collection of objects.)

> Have you read "The Hobbit"?  Do you remember what Treebeard told Bilbo
> about his name?

(Actually it was _The Two Towers_, and it was Merry & Pippin, not Bilbo,
but it's still a good analogy.  )

Richard



Re: OT: Language War (Re: "C" Manual)

2002-01-07 Thread dman
On Sun, Jan 06, 2002 at 04:51:14PM -0800, Erik Steffl wrote:
| dman wrote:
| > 
| > On Sat, Jan 05, 2002 at 09:38:01PM -0800, Erik Steffl wrote:
| > | dman wrote:
| > ...
| > | > In C/C++ there is an invariant on strings ("char*", which is
| > | > essentially equivalent to "char[]") that they end with a NUL byte.
| > |
| > |   no, that's not true.
| > 
| > It is true.  A type is more than the name a compiler gives it.  A type
| 
| the type in C is only what type in C is. what the type is in your head
| is irrelevant.

No, a type is a certain thing, irrespective of the language you are
currently working with.  A type is a higher-level thing than a
compiler is.  Each languge has its own way of (trying) to express
types, but by necessity each is limited and incomplete.  Will you try
and convince me that python has no types?  You never tell the compiler
the type of object an identifier will refer to, but you still get
TypeError exceptions.

[...] 
| > | > A better approach is to use classes with set interfaces to ensure that
| > | > any invariants on the type can't be broken, but C doesn't have such
| > | > capabilities.  It is also better if the system can perform those
| > | > checks for you, but it isn't always possible or feasible.
| > | >
| > | > Eiffel provides a way for you to specify the invariants,
| > | > preconditions, and postconditions of portions of code (classes and
| > | > methods); but even so, not everything can be checked.
| > |
| > |   that's all good, but the point here is that it's not type issue. the
| > | type of variable and the domain of valid values are two separate issues
| > | (well, you could define a new type where type would be the same as valid
| > | domain but it's not always possible).
| > 
| > It is a type issue.  As stated above a type is more than a name; it
| > also includes all the invariants that must be kept.
| 
|   type is what given language considers a type. not what you (or I)
| consider a type. and also, you need to differentiate between types and
| domains of valid values (not sure if these are correct english math
| terms but think of your math classes (mathematical analysis) and I'm
| quite sure you'll know what that menas - most of math fairy tales starts
| with: for all x, y from N, where x | > | > Therefore, I claim that type safety is a more fundamental concept 
than
| > | > | > resource mangement.
| > | > |
| > | > |   well, why?
| > | >
| > | > See the above discussion of invariants, preconditions, and
| > | > postconditions.  Those are part of a "type", but have little to do
| > | > with resource management.
| > |
| > |   above discussion is irrelevant to the issue at hand, there is no such
| > | type in C and the preconditions are only for specific functions (and are
| > | more part of specifying valid domain that valid types).
| > |
| > |   if you don't believe it, just check it again - there is no type error
| > | in the C code quoted above. it's the value that's wrong for given
| > | function (operator <<).
| > 
| > I agree that the C compiler has an incomplete notion of 'types' (based
| > solely on name) which is why *it* doesn't tell you that you made an
| > error.
| 
|   yes, but:
| 
|   solely on name: not sure what you mean here, you refer to types by
| names in all languages,

In python you only refer to a type by referencing a factory for that
type (class objects are factories for their own instances).  Eg the
function you have below would be written as :

def operator_star( i , j ) :
if i < j : segfault()
else : return float( i*j )

note that there is no mention of the types of i, j, or the return
value.  The closest it comes is calling a function named 'float' that
converts it's argument to a floating point object.

| it's just that definition of type might be more
| complicated, in C you have certain primitive types that you can use to
| construct new type given specific operations (typedef, struct, ...), in
| some languages you might have a way to specify type using 'procedural'
| conditions.

'typedef' in C is the same as #define, except for the binding of, eg,
'*' to each one.  It just creates a new name for the same old thing.

Ex :
#define string char*
string s ;
string t ,  u  ;

typedef char* string ;
string s ;
string t , u ;

the only difference is the incorrect application of '*' in the 3rd
line of the first example.

'struct' creates a name that refers to a combination of other names,
but still that is not the complete type.

|   in the example above (sort of, it's not quoted anymore) there is only
| one variable involved and so you can try to make it an issue of type,
| why is it wrong and why you have to consider types and domains of valid
| values separately is clear when using more than one variable.
| 
|   imagine that you have a binary operator that only works for certain
| values of parameters:

Ok :

| int operator * (int i, int j)
| {
|   if(i

Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread Eric G . Miller
On Sun, 6 Jan 2002 16:48:31 -0500 (EST), William T Wilson <[EMAIL PROTECTED]> 
wrote:

> On Sat, 5 Jan 2002, Eric G.Miller wrote:
> 
> > is one of the reasons pointers to char are so common.  However, there
> > is a little trick that's guaranteed to always work:
> > 
> >  struct foo {
> > size_t length;
> > char str[1];
> >  };

[snip]

> It doesn't look particularly guaranteed to me.  You're really allocating
> *three* pieces of memory here - one for the struct foo, one for the
> 1-character array chr, and one for the rest of the string.  Your example
> assumes that chr will be located in memory immediately after foo - which
> it probably will, but it might not.  It could be anywhere, the language
> makes no guarantee.  The compiler might even choose to put the 1-char
> array before foo, so you can't use it without overwriting your struct

As a follow up.  I checked around.  According to the C FAQ (1995) #2.6, this
behavior was determined not to be strictly conforming but was believed
to be portable to all known implementations.  ISO C99 defines it as
a valid construct (6.5.2.1 #15-17).  It also allows that the array
may be an incomplete type  "char str[];".  The sizeof() operator will always
treat the struct as if the array had been defined as having a single
element.

Anyway, thanks for making me check my facts.  Sometimes we get ideas about
things that aren't necessarily true...

-- 
Eric G. Miller 



Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread dman
On Sun, Jan 06, 2002 at 04:48:24PM -0800, Eric G. Miller wrote:
| On Sun, 6 Jan 2002 16:48:31 -0500 (EST), William T Wilson <[EMAIL PROTECTED]> 
wrote:
| 
| > On Sat, 5 Jan 2002, Eric G.Miller wrote:
| > 
| > > is one of the reasons pointers to char are so common.  However, there
| > > is a little trick that's guaranteed to always work:
| > > 
| > >  struct foo {
| > >   size_t length;
| > >   char str[1];
| > >  };
| > > 
| > >  ...
| > > 
| > > struct foo * str_to_foo(char *a)
| > > {
| > >   size_t len = strlen (a);
| > >   struct foo *bar = malloc (sizeof(struct foo) + len);
| > >   if (bar) {
| > > bar->length = len;
| > > memcpy (bar->str, a, len);  /* bar->str now not NUL terminated */
| > >   }
| > >   return bar;
| > > } 
| > 
| > It doesn't look particularly guaranteed to me.
|
| > You're really allocating *three* pieces of memory here - one for
| > the struct foo, one for the 1-character array chr, and one for the
| > rest of the string.

One piece -- there is only 1 malloc() call.

| > Your example assumes that chr will be located in memory
| > immediately after foo - which it probably will, but it might not.
| > It could be anywhere, the language makes no guarantee.  The
| > compiler might even choose to put the 1-char array before foo, so
| > you can't use it without overwriting your struct

Good thought, but I think Eric is right here

| It *is* one chunk of memory, and it does work. The compiler is not allowed
| to reorder the members of the struct.  A pointer to the struct is always
| guaranteed to be a pointer to the first element, as well.

GTK+ achieves inheritance by (ab)using this feature.  Example :

struct Base
{
int member1 ;
}

struct Child
{
struct Base b ;
int member2 ;
}

you can then case a Child* to a Base* and it will work.  (their macros
that do the casting for you do some sort of check first though)

| The compiler may add padding between elements of the struct for
| alignment purposes, but we don't need to care about that
| (sizeof(struct foo)) will do the right thing.  If you don't believe
| me, ask the guru's on comp.lang.c.  This extra space allocation for
| structs trick, only works for the last member of the struct
| (obviously), and it should be declared as an array with one element
| (it's not limited to char's).

Though technically that 'len' should be multiplied by 'sizeof(char)'
just for safety/clarity (even though sizeof(char) is 1).

| > > The benefit is being able to use one malloc vs. two (for any similarly
| > 
| > This is a benefit why? :}
| 
| Calls to malloc are relatively expensive.  It's more efficient to use
| fewer large allocations than many small ones.  Also, makes management
| of the memory a little simpler (only one chunk of memory to worry about).

I was thinking of the redundancy of calling realloc() shortly after
calling malloc(), but I had something different (but not wholly clear)
in mind.

-D

-- 

Consider what God has done:
Who can straighten what He has made crooked?
Ecclesiastes 7:13



Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread Erik Steffl
dman wrote:
> 
> On Sat, Jan 05, 2002 at 09:38:01PM -0800, Erik Steffl wrote:
> | dman wrote:
> ...
> | > In C/C++ there is an invariant on strings ("char*", which is
> | > essentially equivalent to "char[]") that they end with a NUL byte.
> |
> |   no, that's not true.
> 
> It is true.  A type is more than the name a compiler gives it.  A type

  the type in C is only what type in C is. what the type is in your head
is irrelevant.

> also includes invariants and pre- and post-conditions of all
> operations on it.

  no, not in C.

> |   char* or char[] are arrays. SOME functions use them in a way that
> | requires '\0' character to be somewhere within allocated space for given
> | array. but that's strictly requirement of value for some pecific
> | functions, it has nothing to do with definition of language.
> |
> |   it is perfectly legal to use character arrays that have no '\0'
> | character (just don't use them in functions that assume the '\0' to be
> | last character to use).
> 
> I agree with you that C/C++ compilers have a limited view on types and
> don't catch errors like the given example where an array of characters
> (that fails to meet the invariants on strings) is handed to a function
> that requires (a precondition) a valid string.  Certainly character
> arrays that aren't strings are legal data types, and you can create

  the string is convenient name for certain values of character array.
it's not a type.

> your own string type.  Remember, though, that a type is more than a
> name.

  for you, maybe. for C, not.

> | > The invariant is an implicit precondition for the operation that was
> | > performed.  The coder above broke that invariant, which means that the
> | > precondition for the operation wasn't met, and the result is
> | > "undefined" (a segfault, if you're lucky).
> |
> |   yes, but that's what was said before. it doesn't have anything to do
> | with types, it is simply bad value.
> 
> A "bad value" is one which fails to meet the invariants of the given
> type, thus it is not "of that type".

  and which C type would that be?

> | just like you cannot divide by zero.
> 
> A precondition to integer and floating point division is that the
> denominator != 0.  If you fail to meet that precondition, the results
> are undefined.  (As a prof of mine likes to say "all bets are off")

  that's precondition of operation, not of type. notice that division
accepts any two numbers (again, think of types and domains of valid
values)

> | > A better approach is to use classes with set interfaces to ensure that
> | > any invariants on the type can't be broken, but C doesn't have such
> | > capabilities.  It is also better if the system can perform those
> | > checks for you, but it isn't always possible or feasible.
> | >
> | > Eiffel provides a way for you to specify the invariants,
> | > preconditions, and postconditions of portions of code (classes and
> | > methods); but even so, not everything can be checked.
> |
> |   that's all good, but the point here is that it's not type issue. the
> | type of variable and the domain of valid values are two separate issues
> | (well, you could define a new type where type would be the same as valid
> | domain but it's not always possible).
> 
> It is a type issue.  As stated above a type is more than a name; it
> also includes all the invariants that must be kept.

  type is what given language considers a type. not what you (or I)
consider a type. and also, you need to differentiate between types and
domains of valid values (not sure if these are correct english math
terms but think of your math classes (mathematical analysis) and I'm
quite sure you'll know what that menas - most of math fairy tales starts
with: for all x, y from N, where x | > | > Therefore, I claim that type safety is a more fundamental concept than
> | > | > resource mangement.
> | > |
> | > |   well, why?
> | >
> | > See the above discussion of invariants, preconditions, and
> | > postconditions.  Those are part of a "type", but have little to do
> | > with resource management.
> |
> |   above discussion is irrelevant to the issue at hand, there is no such
> | type in C and the preconditions are only for specific functions (and are
> | more part of specifying valid domain that valid types).
> |
> |   if you don't believe it, just check it again - there is no type error
> | in the C code quoted above. it's the value that's wrong for given
> | function (operator <<).
> 
> I agree that the C compiler has an incomplete notion of 'types' (based
> solely on name) which is why *it* doesn't tell you that you made an
> error.

  yes, but:

  solely on name: not sure what you mean here, you refer to types by
names in all languages, it's just that definition of type might be more
complicated, in C you have certain primitive types that you can use to
construct new type given specific operations (typedef, struct, ...), in
some languages you might have a way to specify type using 'proced

Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread Eric G . Miller
On Sun, 6 Jan 2002 16:48:31 -0500 (EST), William T Wilson <[EMAIL PROTECTED]> 
wrote:

> On Sat, 5 Jan 2002, Eric G.Miller wrote:
> 
> > is one of the reasons pointers to char are so common.  However, there
> > is a little trick that's guaranteed to always work:
> > 
> >  struct foo {
> > size_t length;
> > char str[1];
> >  };
> > 
> >  ...
> > 
> > struct foo * str_to_foo(char *a)
> > {
> >   size_t len = strlen (a);
> >   struct foo *bar = malloc (sizeof(struct foo) + len);
> >   if (bar) {
> > bar->length = len;
> > memcpy (bar->str, a, len);  /* bar->str now not NUL terminated */
> >   }
> >   return bar;
> > } 
> 
> It doesn't look particularly guaranteed to me.  You're really allocating
> *three* pieces of memory here - one for the struct foo, one for the
> 1-character array chr, and one for the rest of the string.  Your example
> assumes that chr will be located in memory immediately after foo - which
> it probably will, but it might not.  It could be anywhere, the language
> makes no guarantee.  The compiler might even choose to put the 1-char
> array before foo, so you can't use it without overwriting your struct

It *is* one chunk of memory, and it does work. The compiler is not allowed
to reorder the members of the struct.  A pointer to the struct is always
guaranteed to be a pointer to the first element, as well.  The compiler
may add padding between elements of the struct for alignment purposes,
but we don't need to care about that (sizeof(struct foo)) will do the
right thing.  If you don't believe me, ask the guru's on comp.lang.c.
This extra space allocation for structs trick, only works for the last
member of the struct (obviously), and it should be declared as an
array with one element (it's not limited to char's).

> Structs have fields.  Use them.

I thought I was.

> > The benefit is being able to use one malloc vs. two (for any similarly
> 
> This is a benefit why? :}

Calls to malloc are relatively expensive.  It's more efficient to use
fewer large allocations than many small ones.  Also, makes management
of the memory a little simpler (only one chunk of memory to worry about).


-- 
Eric G. Miller 



Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread William T Wilson
On Sat, 5 Jan 2002, Eric G.Miller wrote:

> is one of the reasons pointers to char are so common.  However, there
> is a little trick that's guaranteed to always work:
> 
>  struct foo {
>   size_t length;
>   char str[1];
>  };
> 
>  ...
> 
> struct foo * str_to_foo(char *a)
> {
>   size_t len = strlen (a);
>   struct foo *bar = malloc (sizeof(struct foo) + len);
>   if (bar) {
> bar->length = len;
> memcpy (bar->str, a, len);  /* bar->str now not NUL terminated */
>   }
>   return bar;
> } 

It doesn't look particularly guaranteed to me.  You're really allocating
*three* pieces of memory here - one for the struct foo, one for the
1-character array chr, and one for the rest of the string.  Your example
assumes that chr will be located in memory immediately after foo - which
it probably will, but it might not.  It could be anywhere, the language
makes no guarantee.  The compiler might even choose to put the 1-char
array before foo, so you can't use it without overwriting your struct

Structs have fields.  Use them.

> The benefit is being able to use one malloc vs. two (for any similarly

This is a benefit why? :}



Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread dman
On Sat, Jan 05, 2002 at 09:38:01PM -0800, Erik Steffl wrote:
| dman wrote:
...
| > In C/C++ there is an invariant on strings ("char*", which is
| > essentially equivalent to "char[]") that they end with a NUL byte.
| 
|   no, that's not true.

It is true.  A type is more than the name a compiler gives it.  A type
also includes invariants and pre- and post-conditions of all
operations on it. 

|   char* or char[] are arrays. SOME functions use them in a way that
| requires '\0' character to be somewhere within allocated space for given
| array. but that's strictly requirement of value for some pecific
| functions, it has nothing to do with definition of language.
| 
|   it is perfectly legal to use character arrays that have no '\0'
| character (just don't use them in functions that assume the '\0' to be
| last character to use).

I agree with you that C/C++ compilers have a limited view on types and
don't catch errors like the given example where an array of characters
(that fails to meet the invariants on strings) is handed to a function
that requires (a precondition) a valid string.  Certainly character
arrays that aren't strings are legal data types, and you can create
your own string type.  Remember, though, that a type is more than a
name.

| > The invariant is an implicit precondition for the operation that was
| > performed.  The coder above broke that invariant, which means that the
| > precondition for the operation wasn't met, and the result is
| > "undefined" (a segfault, if you're lucky).
| 
|   yes, but that's what was said before. it doesn't have anything to do
| with types, it is simply bad value.

A "bad value" is one which fails to meet the invariants of the given
type, thus it is not "of that type".

| just like you cannot divide by zero.

A precondition to integer and floating point division is that the
denominator != 0.  If you fail to meet that precondition, the results
are undefined.  (As a prof of mine likes to say "all bets are off")

| > A better approach is to use classes with set interfaces to ensure that
| > any invariants on the type can't be broken, but C doesn't have such
| > capabilities.  It is also better if the system can perform those
| > checks for you, but it isn't always possible or feasible.
| > 
| > Eiffel provides a way for you to specify the invariants,
| > preconditions, and postconditions of portions of code (classes and
| > methods); but even so, not everything can be checked.
| 
|   that's all good, but the point here is that it's not type issue. the
| type of variable and the domain of valid values are two separate issues
| (well, you could define a new type where type would be the same as valid
| domain but it's not always possible).

It is a type issue.  As stated above a type is more than a name; it
also includes all the invariants that must be kept.

| > | > Therefore, I claim that type safety is a more fundamental concept than
| > | > resource mangement.
| > |
| > |   well, why?
| > 
| > See the above discussion of invariants, preconditions, and
| > postconditions.  Those are part of a "type", but have little to do
| > with resource management.
| 
|   above discussion is irrelevant to the issue at hand, there is no such
| type in C and the preconditions are only for specific functions (and are
| more part of specifying valid domain that valid types).
| 
|   if you don't believe it, just check it again - there is no type error
| in the C code quoted above. it's the value that's wrong for given
| function (operator <<).

I agree that the C compiler has an incomplete notion of 'types' (based
solely on name) which is why *it* doesn't tell you that you made an
error.

-D

-- 

Python is executable pseudocode. Perl is executable line noise.



Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread Richard Cobbe
Lo, on Friday, January 4, David Jardine did write:

> On Thu, Jan 03, 2002 at 05:34:00PM -0600, Richard Cobbe wrote:
> > 
> > Yes, it *is* types.  Remember the definition of type-safety:
> > 
> > If an expression E is determined at compile time to have type T,
> > then evaluating E will have one of two results:
> > 
> > 1) The value of E is a valid object of type T and not just some
> >random collection of bits we're misinterpreting as a T.
> > 2) a well-defined runtime error occurs (e.g., Java's
> >ArrayBoundsException).
> > 
> An ArrayBoundsException is not a question of type in Java.  An
> array of two chars is exactly the same type as an array of two
> thousand chars.  A two-dimensional array of chars, on the other
> hand, is a different type from a three-dimensional one.

Consider the Java declaration
int a[]

The issue above is not the type of a, but rather the type of a[45].
The compiler determines that a[45] has type int---try passing it as an
argument to a method that expects a string, and you'll get a compilation
error, regardless of the actual number of elements in a.

Since the compiler has determined a[45] to have type int, then
evaluating that expression better darned well produce a real-live int.
If it can't (because a only has 4 elements), then, to preserve
type-safety, Java signals an error.

Richard



Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread Richard Cobbe
Lo, on Friday, January 4, David Teague did write:

> On Thu, 3 Jan 2002, Richard Cobbe wrote:
> 
> > Not in the general case, no.
> > 
> > std::string *s = new string("foo");
> > std::string *s2 = s;
> > 
> > delete s;
> > 
> > If we assume a variant of C++ that extends delete to set its
> > argument pointer to NULL, you still have the problem of s2 hanging
> > around.  In the general case, it's not so obvious that you've got
> > two pointers to reset.

> The allocated memory is released to the free store manager. There is
> no leak.

The original goal was avoiding bogus pointers rather than avoiding
memory leaks.  The suggestion to which I was responding was that C/C++
automatically zero out a pointer when you deallocate the memory to which
that pointer refers.

> However, you have the dangling pointer s2, which you must not apply
> the delete operator to again. This will result in at least a
> segmenatation fault.

It *might* segfault---if you're lucky.
 
> For safety's sake, assign 0 to s2, so it will receive the null
> pointer value.

My point was that *finding* s2 is extremely difficult in the general
case, for the runtime system, the compiler, or the programmer.  In fact,
in certain situations, the programmer can't set s2 back to the null
pointer, as it's not in scope at the point of the deallocation (e.g., a
local variable in the function a few levels back up the call stack).

Richard



Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread Erik Steffl
dman wrote:
> 
> On Thu, Jan 03, 2002 at 09:39:09PM -0600, Gary Turner wrote:
> | On Thu, 03 Jan 2002 17:34:00 -0600 (CST), Richard Cobbe wrote:
...
> | >char str[] = { 'b', 'a', 'd', ' ', 's', 't', 'r', 'i', 'n', 'g' };
> | >// note the lack of a terminating '\0'!
> | >cout << str;
...
> | Neophyte that I am, I feel like I'm bringing a knife to this gunfight.
> | This example looks to be a cheat, in that you've defined an array and
> | then treated it as a string (legal).  Had you defined a string, it would
> | be null terminated and index addressable.
> 
> He did define a string.  In C++ there are 3 ways of defining a string
> (in C there are 2).  There is "char[]", "char*" and "std::string".
> The latter is the best way because it provides the most protection.

  no, he did not define a string, he defined an array of chars, which is
often used as string, string manipulating functions in standard
libraries assume that a pointer to char (or char array) will be ended by
'\0' but a char array that does not end with zero is just as good char
array as any other (as far as its type goes).

  therefore when the function fails (the one that assumes '\0' at the
end), it does not fail because of type problem but because of the wrong
value.

  there is no such thing as string type in c or c++ language (there is a
string in c++ standard libraries).

erik



Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread Gary Turner
On Fri, 04 Jan 2002 14:28:46 -0500, dman wrote:

>On Thu, Jan 03, 2002 at 09:39:09PM -0600, Gary Turner wrote:
>| On Thu, 03 Jan 2002 17:34:00 -0600 (CST), Richard Cobbe wrote:
>| >
>| >Lo, on Thursday, January 3, Erik Steffl did write:
>| >
>| >> what's the difference? the point is you can assign almost anything to
>| >> anything, and yet there is no segfault - i.e. the strength of types has
>| >> nothing (sort of) to do with segfaults... the resource allocation is
>| >> crucial...
>| >
>| >Type safety (plus dynamic allocation) implies advanced memory
>| >management.  The converse is not true: you can slap Boehm's conservative
>| >GC onto a C++ program, but you can still get segmentation faults:
>| >
>| >char str[] = { 'b', 'a', 'd', ' ', 's', 't', 'r', 'i', 'n', 'g' };
>| >// note the lack of a terminating '\0'!
>| >cout << str;
>| >
>| 
>| >No allocation issues involved.  As Ben Collins pointed out elsewhere in
>| >this thread (bit of a tree-shaped thread, isn't it?), this won't
>| >necessarily cause a segfault, but it can.  It's also a violation of
>| >type-safety: cout expects a null-terminated string, and as far as the
>| >compiler is concerned, str fits this.  However, there's no runtime check
>| >in the output routine to verify that this is, in fact, the case.  Ooops.
>| 
>| Neophyte that I am, I feel like I'm bringing a knife to this gunfight.
>| This example looks to be a cheat, in that you've defined an array and
>| then treated it as a string (legal).  Had you defined a string, it would
>| be null terminated and index addressable.
>
>He did define a string.  In C++ there are 3 ways of defining a string
>(in C there are 2).  There is "char[]", "char*" and "std::string".
Isn't 'char*' redundant, since an array var is a pointer by definition?
If I'm showing my ignorance again, I apologize.
>The latter is the best way because it provides the most protection.
>
I disagree.  He defined an array of characters, just as 
int a[] = 1,2,3;
is an array of integers.
To define a string he should say
char a[] = "bad string";
or
char a[11]; 
Either of these forms would give him a properly terminated 'string'.
Without the terminating \0, string functions will go merrily gonzo.
>
>| The fact that you *can* screw up doesn't mean you have to.
>
>True, but when choosing a language for a given project, wouldn't you
>rather use one that gives you fewer guns to shoot yourself with?  I
>know I would :-).  (this is not to say that C is not a good language,
>but it does have its place)
>
Isn't that true of any tool?  But you choose the language you think will
best serve your needs (and that could come down to strictly legacy).  It
is still the writer's responsibility to honor the function's
expectations and create the necessary error checking routines before
they shoot the wheels off.
>
>| >Therefore, I claim that type safety is a more fundamental concept than
>| >resource mangement.
>|
>| Is there a difference?  Again, my ignorance knows no bounds.  Doesn't
search for: knowing replace with: knows^(couldn't stand the
bad grammar ;p )
>| the type define the required allocation?
>
>A given type will have certain allocation requirments (ie size, which
>is why a C++ class can't contain a non-pointer to a not-yet-defined
>class or to a class that contains the current class).
>
>| In the example above, is it a type, or allocation error if the
>| *programmer* decides to access str[10]?  (If I counted right, that's
>| the next byte after the array bloc.)
>
>I think that would be an allocation error since it is illegal to
>access memory outside the allocated bounds.
>
It would be nice if c/c++ included array bounds checking, but since it
doesn't, the programmer *must* check and control it himself.  The array
is properly allocated.  It is the programmer who decided to go into
unmapped territory.  If only Picard would release...
>-D
gt
Yes I fear I am living beyond my mental means--Nash



Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread dman
On Fri, Jan 04, 2002 at 11:50:04PM -0600, Gary Turner wrote:
| On Fri, 04 Jan 2002 14:28:46 -0500, dman wrote:
| >On Thu, Jan 03, 2002 at 09:39:09PM -0600, Gary Turner wrote:
| >| On Thu, 03 Jan 2002 17:34:00 -0600 (CST), Richard Cobbe wrote:
| >| >Lo, on Thursday, January 3, Erik Steffl did write:
...
| >| >Type safety (plus dynamic allocation) implies advanced memory
| >| >management.  The converse is not true: you can slap Boehm's conservative
| >| >GC onto a C++ program, but you can still get segmentation faults:
| >| >
| >| >char str[] = { 'b', 'a', 'd', ' ', 's', 't', 'r', 'i', 'n', 'g' };
| >| >// note the lack of a terminating '\0'!
| >| >cout << str;

| >| This example looks to be a cheat, in that you've defined an array and
| >| then treated it as a string (legal).  Had you defined a string, it would
| >| be null terminated and index addressable.
| >
| >He did define a string.  In C++ there are 3 ways of defining a string
| >(in C there are 2).  There is "char[]", "char*" and "std::string".
|
| Isn't 'char*' redundant, since an array var is a pointer by definition?

Almost.  A char[] behaves like a char*, but you can't assign to a
char[] the way you can with a char*.  Eg :

char  t[5] ;
t = malloc( 6*sizeof(char) ) ;

The assignment yields
incompatible types in assignment
when you try and compile it.

| If I'm showing my ignorance again, I apologize.
| >The latter is the best way because it provides the most protection.
|
| I disagree.  He defined an array of characters, just as 
| int a[] = 1,2,3;
| is an array of integers.

Right.  But the point is the type system is more than that.  

| To define a string he should say
| char a[] = "bad string";

This would work, but how is this _type_ different from the type above?
Both are char[]!.

| or
| char a[11]; 

Nope.  This gives you contiguous space for 11 chars, but doesn't
initialize it to any value (or ensure it is NUL-termiated).

| Either of these forms would give him a properly terminated 'string'.

Meaning that if you dance just right, the invariants are met, but if
you slip a little, BOOM!

| Without the terminating \0, string functions will go merrily gonzo.

Right, that is part of the invariant on C-strings.

| >| The fact that you *can* screw up doesn't mean you have to.
| >
| >True, but when choosing a language for a given project, wouldn't you
| >rather use one that gives you fewer guns to shoot yourself with?  I
| >know I would :-).  (this is not to say that C is not a good language,
| >but it does have its place)
|
| Isn't that true of any tool?

Yes.

| is still the writer's responsibility to honor the function's
| expectations and create the necessary error checking routines before
| they shoot the wheels off.

If they can.  You can't check a random char* or char[] to ensure it
is a valid string.  If you could, then the string functions would and
they wouldn't segfault.  (Think : if the block of memory ("string")
doesn't contain a NUL character, how do you know where the block of
memory ends?)

| >| In the example above, is it a type, or allocation error if the
| >| *programmer* decides to access str[10]?  (If I counted right, that's
| >| the next byte after the array bloc.)
| >
| >I think that would be an allocation error since it is illegal to
| >access memory outside the allocated bounds.
|
| It would be nice if c/c++ included array bounds checking, but since it
| doesn't, the programmer *must* check and control it himself.  The array

It is impossible to check it at runtime.  See above.  To work around
this, you can avoid arrays altogether and use, for example GList from
the GLib library.

-D

-- 

In my Father's house are many rooms; if it were not so, I would have
told you.  I am going there to prepare a place for you.  And if I go and
prepare a place for you, I will come and take you to be with me that you
also may be where I am.
John 14:2-3 



Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread Eric G . Miller
On Fri, 04 Jan 2002 23:50:04 -0600, Gary Turner <[EMAIL PROTECTED]> wrote:

[snip]
> >He did define a string.  In C++ there are 3 ways of defining a string
> >(in C there are 2).  There is "char[]", "char*" and "std::string".
> Isn't 'char*' redundant, since an array var is a pointer by definition?
> If I'm showing my ignorance again, I apologize.

A foo[] and foo* are not the same.  The first implies automatic
allocation for some number of "foo's", while the second is only
a pointer to foo. That an array decays to a pointer to it's first
element in function calls doesn't make it the same as a variable
declared as a pointer. For instance, trying to free() a pointer
to an array leads to UB. You also can't resize an array, which
is one of the reasons pointers to char are so common.  However,
there is a little trick that's guaranteed to always work:

 struct foo {
size_t length;
char str[1];
 };

 ...

struct foo * str_to_foo(char *a)
{
  size_t len = strlen (a);
  struct foo *bar = malloc (sizeof(struct foo) + len);
  if (bar) {
bar->length = len;
memcpy (bar->str, a, len);  /* bar->str now not NUL terminated */
  }
  return bar;
} 

The benefit is being able to use one malloc vs. two (for any similarly
arranged struct).  The idiom can be useful for reading/writing binary
files as well.

> >The latter is the best way because it provides the most protection.
> >
> I disagree.  He defined an array of characters, just as 
> int a[] = 1,2,3;
> is an array of integers.
> To define a string he should say
> char a[] = "bad string";
> or
> char a[11]; 
> Either of these forms would give him a properly terminated 'string'.
> Without the terminating \0, string functions will go merrily gonzo.

Of course, the point of the example was that the array was *not*
NUL terminated as required by C "strings", and therefore passing
it to a function expecting a NUL terminated string, results in UB.

Also, "int a[] = 1,2,3;" will *not* do what you expect.  In fact,
it won't compile at all.  I think you meant "int a[] = {1,2,3};".

Is this still debian-user?  I'm having comp.lang.c flashbacks 8^)

-- 
Eric G. Miller 



Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread Eric G . Miller
On Fri, 4 Jan 2002 20:17:08 -0500, dman <[EMAIL PROTECTED]> wrote:

> On Thu, Jan 03, 2002 at 08:43:55AM -0800, Craig Dickson wrote:
> | dman wrote:
> | 
> | > However the thing to remember about macros is that they are textual
> | > substituation.  It is effectively the same thing as writing the
> | > assignment yourself.
> | 
> | So?
> 
> The point there was that it isn't a feature of the language.

Well, actually the C preprocessor *is* a part of the language.  So, the
hell of C, and C++ by extension, means you really need to learn two
languages...  But the preprocessor macro language is even more confusing
than the C part.  Consider the # and ## operators.  More than simple
textual substitution is going on.

-- 
Eric G. Miller 



Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread Erik Steffl
dman wrote:
> 
> On Thu, Jan 03, 2002 at 09:10:56PM -0800, Erik Steffl wrote:
> | Richard Cobbe wrote:
> | >
> | > Lo, on Thursday, January 3, Erik Steffl did write:
> | >
> | > > what's the difference? the point is you can assign almost anything to
> | > > anything, and yet there is no segfault - i.e. the strength of types has
> | > > nothing (sort of) to do with segfaults... the resource allocation is
> | > > crucial...
> | >
> | > Type safety (plus dynamic allocation) implies advanced memory
> | > management.  The converse is not true: you can slap Boehm's conservative
> | > GC onto a C++ program, but you can still get segmentation faults:
> | >
> | > char str[] = { 'b', 'a', 'd', ' ', 's', 't', 'r', 'i', 'n', 'g' };
> | > // note the lack of a terminating '\0'!
> | > cout << str;
> | >
> | > No allocation issues involved.  As Ben Collins pointed out elsewhere in
> | > this thread (bit of a tree-shaped thread, isn't it?), this won't
> | > necessarily cause a segfault, but it can.  It's also a violation of
> | > type-safety: cout expects a null-terminated string, and as far as the
> | > compiler is concerned, str fits this.  However, there's no runtime check
> | > in the output routine to verify that this is, in fact, the case.  Ooops.
> |
> |   that's not really good analysis of what's actually going on. the str
> | is actually array of characters,
> 
> yes,
> 
> | it's not really a string
> 
> it is.  More formally it is a C-string, as opposed to std::string

  no, it is not a string as there is no such type in C language. it is
used as string in many functions. but it is not a string, it is an array
of characters.

  the C-string is '\0'-terminated array of characters but that's NOT a C
type.

> | (there's no such thing in c++ language,
> 
> Then what is the type of the following expression ?
> 
> "hello world"

  it is an array of characters. const (both it's address and value).

> It is a string.  The compiler calls it "const char[11]".

  it is what compiler calls it, it's not a string.

> | there is a string as part of standard library (runtime?-))
> 
> There are many "types" of string in C++.

  ? in C++ language there are no strings. in C++ standard libraries
there is a string class (template). you can, of course, define your own
string types in C++

> |   so the problem here is that the actual value of the variable is not
> | according the specs for cout, it's of correct type (char *). And str
> | certainly evaluates to char *, not a random collection of bits (it's not
> | really a char * but it doesn't matter in this case)
> |
> |   I don't see any type related problem here. cout assumes something
> | about the value, it's not true, BOOM!
> 
> In C/C++ there is an invariant on strings ("char*", which is
> essentially equivalent to "char[]") that they end with a NUL byte.

  no, that's not true.

  char* or char[] are arrays. SOME functions use them in a way that
requires '\0' character to be somewhere within allocated space for given
array. but that's strictly requirement of value for some pecific
functions, it has nothing to do with definition of language.

  it is perfectly legal to use character arrays that have no '\0'
character (just don't use them in functions that assume the '\0' to be
last character to use).

> The invariant is an implicit precondition for the operation that was
> performed.  The coder above broke that invariant, which means that the
> precondition for the operation wasn't met, and the result is
> "undefined" (a segfault, if you're lucky).

  yes, but that's what was said before. it doesn't have anything to do
with types, it is simply bad value. just like you cannot divide by zero.

> A better approach is to use classes with set interfaces to ensure that
> any invariants on the type can't be broken, but C doesn't have such
> capabilities.  It is also better if the system can perform those
> checks for you, but it isn't always possible or feasible.
> 
> Eiffel provides a way for you to specify the invariants,
> preconditions, and postconditions of portions of code (classes and
> methods); but even so, not everything can be checked.

  that's all good, but the point here is that it's not type issue. the
type of variable and the domain of valid values are two separate issues
(well, you could define a new type where type would be the same as valid
domain but it's not always possible).

> | > Therefore, I claim that type safety is a more fundamental concept than
> | > resource mangement.
> |
> |   well, why?
> 
> See the above discussion of invariants, preconditions, and
> postconditions.  Those are part of a "type", but have little to do
> with resource management.

  above discussion is irrelevant to the issue at hand, there is no such
type in C and the preconditions are only for specific functions (and are
more part of specifying valid domain that valid types).

  if you don't believe it, just check it again - there is no type error
in the C code quoted a

Re: OT: Language War (Re: "C" Manual)

2002-01-06 Thread Erik Steffl
Gary Turner wrote:
> 
> On Fri, 04 Jan 2002 14:28:46 -0500, dman wrote:
> 
> >On Thu, Jan 03, 2002 at 09:39:09PM -0600, Gary Turner wrote:
> >| On Thu, 03 Jan 2002 17:34:00 -0600 (CST), Richard Cobbe wrote:
> >| >
> >| >Lo, on Thursday, January 3, Erik Steffl did write:
> >| >
> >| >> what's the difference? the point is you can assign almost anything to
> >| >> anything, and yet there is no segfault - i.e. the strength of types has
> >| >> nothing (sort of) to do with segfaults... the resource allocation is
> >| >> crucial...
> >| >
> >| >Type safety (plus dynamic allocation) implies advanced memory
> >| >management.  The converse is not true: you can slap Boehm's conservative
> >| >GC onto a C++ program, but you can still get segmentation faults:
> >| >
> >| >char str[] = { 'b', 'a', 'd', ' ', 's', 't', 'r', 'i', 'n', 'g' };
> >| >// note the lack of a terminating '\0'!
> >| >cout << str;
> >| >
> >|
> >| >No allocation issues involved.  As Ben Collins pointed out elsewhere in
> >| >this thread (bit of a tree-shaped thread, isn't it?), this won't
> >| >necessarily cause a segfault, but it can.  It's also a violation of
> >| >type-safety: cout expects a null-terminated string, and as far as the
> >| >compiler is concerned, str fits this.  However, there's no runtime check
> >| >in the output routine to verify that this is, in fact, the case.  Ooops.
> >|
> >| Neophyte that I am, I feel like I'm bringing a knife to this gunfight.
> >| This example looks to be a cheat, in that you've defined an array and
> >| then treated it as a string (legal).  Had you defined a string, it would
> >| be null terminated and index addressable.
> >
> >He did define a string.  In C++ there are 3 ways of defining a string
> >(in C there are 2).  There is "char[]", "char*" and "std::string".
> Isn't 'char*' redundant, since an array var is a pointer by definition?
> If I'm showing my ignorance again, I apologize.

  it's not exactly the same, one thing is that you cannot change where
the array points to, the other difference is how they are treated by
sizeof (there might be other differences).

> >The latter is the best way because it provides the most protection.
> >
> I disagree.  He defined an array of characters, just as
> int a[] = 1,2,3;
> is an array of integers.
> To define a string he should say
> char a[] = "bad string";
> or
> char a[11];

  the last one does not zero-terminate the array.

  and btw in all cases the array of characters was defined. in some
cases the array is zero-terminated and can be used with certain
functions that assume it to be zero-terminated. but they are all of same
type.

...
> >I think that would be an allocation error since it is illegal to
> >access memory outside the allocated bounds.
> >
> It would be nice if c/c++ included array bounds checking, but since it
> doesn't, the programmer *must* check and control it himself.  The array
> is properly allocated.  It is the programmer who decided to go into
> unmapped territory.  If only Picard would release...

  in c++ you can (should) use the template class (or string, which is
template instantiated for char) instead of array of characters. the
string class takes cares of checking the length etc.

erik



Re: OT: Language War (Re: "C" Manual)

2002-01-05 Thread dman
On Thu, Jan 03, 2002 at 08:43:55AM -0800, Craig Dickson wrote:
| dman wrote:
| 
| > However the thing to remember about macros is that they are textual
| > substituation.  It is effectively the same thing as writing the
| > assignment yourself.
| 
| So?

The point there was that it isn't a feature of the language.

| > inline functions are really no better than macros, and can even cause
| > bugs (though surely that's just a sign of a buggy compiler).
| 
| I'm not that familiar with how inline is used in C, but in C++, it's
| silly to say that inlines are no better than macros. Inlines are
| type-safe, macros aren't;

Macros are type-safe to the extent that their usage corresponds with
their intent.  The only problem with macros is that very little checks
them.  Using macros in C/C++ starts to approach the way python objects
are used, however in python the types are checked at runtime.

| inlines can be members of a class or namespace, macros can't.

True.

| And you're right that any bugs resulting from the "inline" keyword
| must result from bugs in the compiler, but that's an argument
| against using buggy compilers, not an argument against inlines.

Right.

| > For a particular school project (C++ required) the profs had a working
| > demo that we could run to verify our output (and clarify anything in
| > the specs).  They compiled it without debug symbols so we couldn't
| > look at it in a debugger and reverse-engineer it.  Their demo would
| > crash with certain malformed input.  One of the profs tried to figure
| > it out, but once it was recompiled with debug symbols (which also
| > turns off inlining, for that compiler at least) the program worked
| > correctly.  They had used inline functions extensively in their
| > code.
| 
| Was this ever tracked down?

Not that I know of.

| There are probably other differences between the debug and non-debug
| builds. Optimizations, perhaps?

Possibly.  When debugging is enabled, optimizations are disabled,
right?

| Working in Win32 with Microsoft C++, I've several times had bugs that
| only happened in non-debug builds. It's never been because of inlines,
| though. Usually subtle timing issues, or a rogue pointer that in a debug
| build was pointing at something harmless.

Wouldn't those bugs be less reproducible?  The assignment was to
design and implement an interpreter for "VSL" (Very Small Language).
The language was very simple, but given my programming experience at
the time it was a significant project.  (if I were to do it now I
would use regexes and a tool like lex/yacc and it would take very
little time)  The bug was that a certain bit of malformed input would
crash the app (or make it misbehave, I'm not certain which) rather
than generate an error message.

| > There's no real point to an inline function, just make it a regular
| > function.  The overhead of a function call isn't very big, especially
| > nowadays.
| 
| The overhead is a lot less than it used to be (at least for the x86
| family; I'm less familiar with others), but it's still non-zero, so it
| still matters in performance-critical code.
| 
| I have always tended to inline trivial class/namespace members as a
| matter of habit, because in some cases the inlining actually results in
| smaller code than a regular function would (no parameter passing
| overhead, and optimizations can be applied to the inlined code as if it
| were part of the function that called it). As with performance, this
| isn't usually all that big a deal these days, but it certainly doesn't
| hurt.

I was putting 'inline' on the smaller functions, but I stopped doing
it when I heard of the problems some people have had with it, and when
I learned that it doesn't improve much (especially compared with the
time spent thinking about it and ensuring that it isn't the cause of a
bug).

-D

-- 

He who belongs to God hears what God says.  The reason you do not hear
is that you do not belong to God.
John 8:47



Re: OT: Language War (Re: "C" Manual)

2002-01-05 Thread dman
On Thu, Jan 03, 2002 at 09:10:56PM -0800, Erik Steffl wrote:
| Richard Cobbe wrote:
| > 
| > Lo, on Thursday, January 3, Erik Steffl did write:
| > 
| > > what's the difference? the point is you can assign almost anything to
| > > anything, and yet there is no segfault - i.e. the strength of types has
| > > nothing (sort of) to do with segfaults... the resource allocation is
| > > crucial...
| > 
| > Type safety (plus dynamic allocation) implies advanced memory
| > management.  The converse is not true: you can slap Boehm's conservative
| > GC onto a C++ program, but you can still get segmentation faults:
| > 
| > char str[] = { 'b', 'a', 'd', ' ', 's', 't', 'r', 'i', 'n', 'g' };
| > // note the lack of a terminating '\0'!
| > cout << str;
| > 
| > No allocation issues involved.  As Ben Collins pointed out elsewhere in
| > this thread (bit of a tree-shaped thread, isn't it?), this won't
| > necessarily cause a segfault, but it can.  It's also a violation of
| > type-safety: cout expects a null-terminated string, and as far as the
| > compiler is concerned, str fits this.  However, there's no runtime check
| > in the output routine to verify that this is, in fact, the case.  Ooops.
| 
|   that's not really good analysis of what's actually going on. the str
| is actually array of characters, 

yes,

| it's not really a string

it is.  More formally it is a C-string, as opposed to std::string

| (there's no such thing in c++ language,

Then what is the type of the following expression ?

"hello world"

It is a string.  The compiler calls it "const char[11]".

| there is a string as part of standard library (runtime?-))

There are many "types" of string in C++.

|   so the problem here is that the actual value of the variable is not
| according the specs for cout, it's of correct type (char *). And str
| certainly evaluates to char *, not a random collection of bits (it's not
| really a char * but it doesn't matter in this case)
| 
|   I don't see any type related problem here. cout assumes something
| about the value, it's not true, BOOM!

In C/C++ there is an invariant on strings ("char*", which is
essentially equivalent to "char[]") that they end with a NUL byte.
The invariant is an implicit precondition for the operation that was
performed.  The coder above broke that invariant, which means that the
precondition for the operation wasn't met, and the result is
"undefined" (a segfault, if you're lucky).  

A better approach is to use classes with set interfaces to ensure that
any invariants on the type can't be broken, but C doesn't have such
capabilities.  It is also better if the system can perform those
checks for you, but it isn't always possible or feasible.

Eiffel provides a way for you to specify the invariants,
preconditions, and postconditions of portions of code (classes and
methods); but even so, not everything can be checked.

| > Therefore, I claim that type safety is a more fundamental concept than
| > resource mangement.
| 
|   well, why?

See the above discussion of invariants, preconditions, and
postconditions.  Those are part of a "type", but have little to do
with resource management.

|   is java type-safe? http://www.research.att.com/~vj/bug.html

Interesting.  (I've only just read the abstract)

-D

-- 

Pleasant words are a honeycomb,
sweet to the soul and healing to the bones.
Proverbs 16:24



Re: OT: Language War (Re: "C" Manual)

2002-01-05 Thread Gary Turner
On Fri, 04 Jan 2002 14:28:46 -0500, dman wrote:

>On Thu, Jan 03, 2002 at 09:39:09PM -0600, Gary Turner wrote:
>| On Thu, 03 Jan 2002 17:34:00 -0600 (CST), Richard Cobbe wrote:
>| >
>| >Lo, on Thursday, January 3, Erik Steffl did write:
>| >
>| >> what's the difference? the point is you can assign almost anything to
>| >> anything, and yet there is no segfault - i.e. the strength of types has
>| >> nothing (sort of) to do with segfaults... the resource allocation is
>| >> crucial...
>| >
>| >Type safety (plus dynamic allocation) implies advanced memory
>| >management.  The converse is not true: you can slap Boehm's conservative
>| >GC onto a C++ program, but you can still get segmentation faults:
>| >
>| >char str[] = { 'b', 'a', 'd', ' ', 's', 't', 'r', 'i', 'n', 'g' };
>| >// note the lack of a terminating '\0'!
>| >cout << str;
>| >
>| 
>| >No allocation issues involved.  As Ben Collins pointed out elsewhere in
>| >this thread (bit of a tree-shaped thread, isn't it?), this won't
>| >necessarily cause a segfault, but it can.  It's also a violation of
>| >type-safety: cout expects a null-terminated string, and as far as the
>| >compiler is concerned, str fits this.  However, there's no runtime check
>| >in the output routine to verify that this is, in fact, the case.  Ooops.
>| 
>| Neophyte that I am, I feel like I'm bringing a knife to this gunfight.
>| This example looks to be a cheat, in that you've defined an array and
>| then treated it as a string (legal).  Had you defined a string, it would
>| be null terminated and index addressable.
>
>He did define a string.  In C++ there are 3 ways of defining a string
>(in C there are 2).  There is "char[]", "char*" and "std::string".
Isn't 'char*' redundant, since an array var is a pointer by definition?
If I'm showing my ignorance again, I apologize.
>The latter is the best way because it provides the most protection.
>
I disagree.  He defined an array of characters, just as 
int a[] = 1,2,3;
is an array of integers.
To define a string he should say
char a[] = "bad string";
or
char a[11]; 
Either of these forms would give him a properly terminated 'string'.
Without the terminating \0, string functions will go merrily gonzo.
>
>| The fact that you *can* screw up doesn't mean you have to.
>
>True, but when choosing a language for a given project, wouldn't you
>rather use one that gives you fewer guns to shoot yourself with?  I
>know I would :-).  (this is not to say that C is not a good language,
>but it does have its place)
>
Isn't that true of any tool?  But you choose the language you think will
best serve your needs (and that could come down to strictly legacy).  It
is still the writer's responsibility to honor the function's
expectations and create the necessary error checking routines before
they shoot the wheels off.
>
>| >Therefore, I claim that type safety is a more fundamental concept than
>| >resource mangement.
>|
>| Is there a difference?  Again, my ignorance knows no bounds.  Doesn't
search for: knowing replace with: knows^(couldn't stand the
bad grammar ;p )
>| the type define the required allocation?
>
>A given type will have certain allocation requirments (ie size, which
>is why a C++ class can't contain a non-pointer to a not-yet-defined
>class or to a class that contains the current class).
>
>| In the example above, is it a type, or allocation error if the
>| *programmer* decides to access str[10]?  (If I counted right, that's
>| the next byte after the array bloc.)
>
>I think that would be an allocation error since it is illegal to
>access memory outside the allocated bounds.
>
It would be nice if c/c++ included array bounds checking, but since it
doesn't, the programmer *must* check and control it himself.  The array
is properly allocated.  It is the programmer who decided to go into
unmapped territory.  If only Picard would release...
>-D
gt
Yes I fear I am living beyond my mental means--Nash



Re: OT: Language War (Re: "C" Manual)

2002-01-04 Thread dman
On Thu, Jan 03, 2002 at 09:39:09PM -0600, Gary Turner wrote:
| On Thu, 03 Jan 2002 17:34:00 -0600 (CST), Richard Cobbe wrote:
| >
| >Lo, on Thursday, January 3, Erik Steffl did write:
| >
| >> what's the difference? the point is you can assign almost anything to
| >> anything, and yet there is no segfault - i.e. the strength of types has
| >> nothing (sort of) to do with segfaults... the resource allocation is
| >> crucial...
| >
| >Type safety (plus dynamic allocation) implies advanced memory
| >management.  The converse is not true: you can slap Boehm's conservative
| >GC onto a C++ program, but you can still get segmentation faults:
| >
| >char str[] = { 'b', 'a', 'd', ' ', 's', 't', 'r', 'i', 'n', 'g' };
| >// note the lack of a terminating '\0'!
| >cout << str;
| >
| 
| >No allocation issues involved.  As Ben Collins pointed out elsewhere in
| >this thread (bit of a tree-shaped thread, isn't it?), this won't
| >necessarily cause a segfault, but it can.  It's also a violation of
| >type-safety: cout expects a null-terminated string, and as far as the
| >compiler is concerned, str fits this.  However, there's no runtime check
| >in the output routine to verify that this is, in fact, the case.  Ooops.
| 
| Neophyte that I am, I feel like I'm bringing a knife to this gunfight.
| This example looks to be a cheat, in that you've defined an array and
| then treated it as a string (legal).  Had you defined a string, it would
| be null terminated and index addressable.

He did define a string.  In C++ there are 3 ways of defining a string
(in C there are 2).  There is "char[]", "char*" and "std::string".
The latter is the best way because it provides the most protection.

| The fact that you *can* screw up doesn't mean you have to.

True, but when choosing a language for a given project, wouldn't you
rather use one that gives you fewer guns to shoot yourself with?  I
know I would :-).  (this is not to say that C is not a good language,
but it does have its place)


| >Therefore, I claim that type safety is a more fundamental concept than
| >resource mangement.
|
| Is there a difference?  Again, my ignorance knowing no bounds.  Doesn't
| the type define the required allocation?

A given type will have certain allocation requirments (ie size, which
is why a C++ class can't contain a non-pointer to a not-yet-defined
class or to a class that contains the current class).

| In the example above, is it a type, or allocation error if the
| *programmer* decides to access str[10]?  (If I counted right, that's
| the next byte after the array bloc.)

I think that would be an allocation error since it is illegal to
access memory outside the allocated bounds.  

-D

-- 

A Microsoft Certified System Engineer is to information technology as a
McDonalds Certified Food Specialist is to the culinary arts.
Michael Bacarella commenting on the limited value of certification.



Re: OT: Language War (Re: "C" Manual)

2002-01-04 Thread David Teague
On Thu, 3 Jan 2002, Richard Cobbe wrote:

> Lo, on Thursday, January 3, William T Wilson did write:
> 
> Not in the general case, no.
> 
> std::string *s = new string("foo");
> std::string *s2 = s;
> 
> delete s;
> 
> If we assume a variant of C++ that extends delete to set its argument
> pointer to NULL, you still have the problem of s2 hanging around.  In
> the general case, it's not so obvious that you've got two pointers to
> reset.


You can always overload new to set its pointer argument to the null
pointer value.

The allocated memory is released to the free store manager. There is
no leak. However, you have the dangling pointer s2, which you must
not apply the delete operator to again. This will result in at least
a segmenatation fault. 

For safety's sake, assign 0 to s2, so it will receive the null
pointer value.

BTW NULL is just the int value 0, it is not a pointer.

--David
David Teague, [EMAIL PROTECTED]
Debian GNU/Linux Because software support is free, timely,
 useful, technically accurate, and friendly.
 (I hope this is all of the above.)

> 





Re: OT: Language War (Re: "C" Manual)

2002-01-04 Thread David Jardine
On Thu, Jan 03, 2002 at 05:34:00PM -0600, Richard Cobbe wrote:
> 
> Yes, it *is* types.  Remember the definition of type-safety:
> 
> If an expression E is determined at compile time to have type T,
> then evaluating E will have one of two results:
> 
> 1) The value of E is a valid object of type T and not just some
>random collection of bits we're misinterpreting as a T.
> 2) a well-defined runtime error occurs (e.g., Java's
>ArrayBoundsException).
> 
An ArrayBoundsException is not a question of type in Java.  An
array of two chars is exactly the same type as an array of two
thousand chars.  A two-dimensional array of chars, on the other
hand, is a different type from a three-dimensional one.

David
> 
> 
> -- 
> To UNSUBSCRIBE, email to [EMAIL PROTECTED] 
> with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]
> 



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread Erik Steffl
Richard Cobbe wrote:
> 
> Lo, on Thursday, January 3, Erik Steffl did write:
> 
> > what's the difference? the point is you can assign almost anything to
> > anything, and yet there is no segfault - i.e. the strength of types has
> > nothing (sort of) to do with segfaults... the resource allocation is
> > crucial...
> 
> Type safety (plus dynamic allocation) implies advanced memory
> management.  The converse is not true: you can slap Boehm's conservative
> GC onto a C++ program, but you can still get segmentation faults:
> 
> char str[] = { 'b', 'a', 'd', ' ', 's', 't', 'r', 'i', 'n', 'g' };
> // note the lack of a terminating '\0'!
> cout << str;
> 
> No allocation issues involved.  As Ben Collins pointed out elsewhere in
> this thread (bit of a tree-shaped thread, isn't it?), this won't
> necessarily cause a segfault, but it can.  It's also a violation of
> type-safety: cout expects a null-terminated string, and as far as the
> compiler is concerned, str fits this.  However, there's no runtime check
> in the output routine to verify that this is, in fact, the case.  Ooops.

  that's not really good analysis of what's actually going on. the str
is actually array of characters, it's not really a string (there's no
such thing in c++ language, there is a string as part of standard
library (runtime?-))

  so the problem here is that the actual value of the variable is not
according the specs for cout, it's of correct type (char *). And str
certainly evaluates to char *, not a random collection of bits (it's not
really a char * but it doesn't matter in this case)

  I don't see any type related problem here. cout assumes something
about the value, it's not true, BOOM!

> Therefore, I claim that type safety is a more fundamental concept than
> resource mangement.

  well, why?

> > that's all interesting, but the point was that the perl type system is
> > as weak as I can imagine yet it doesn't lead to segfaults... it's the
> > resource allocation!
> 
> Type safety != `strong' types.  They're orthogonal.  (Well, sort of.  It
> turns out that `strong types' isn't a very well-defined concept;
> language researchers prefer to discuss compile-time type verification.
> *That* definitely has nothing to do with type safety.)
> 
> > If you cannot make sure that MyUserType variable will only be assigned
> > MyUserType values then you have (almost) NO type safety.
> 
> That's only meaningful if you can declare a variable to be MyUserType at
> runtime.  This does not apply to a whole variety of languages, many of
> which are still type-safe.
> 
> (I think I'm just going to decide that Perl's type system is on crack.

  pretty much, it's quite strange.

> But what do you expect when a linguist designs a programming language?)

  perl?

> > > In any case, memory allocation errors aren't the only cause of
> > > segmentation faults---how about walking off the end of an array?  Here,
> > > I claim that Perl *does* maintain type-safety, although in a seriously
> > > fscked-up way: it simply expands the array to make the reference valid.
> >
> >   it's not the types! it doesn't care about types at all. it just makes
> > sure you always have a place to store whatever you are about to store.
> > what does that have with types? not much. it has to know what are you
> > trying to store but it doesn't care at all what was there before, what's
> > the type of variable where you are storing it. again, I find it pretty
> > strange to call that kind of behaviour 'type safety'.
> 
> Yes, it *is* types.  Remember the definition of type-safety:
> 
> If an expression E is determined at compile time to have type T,
> then evaluating E will have one of two results:
> 
> 1) The value of E is a valid object of type T and not just some
>random collection of bits we're misinterpreting as a T.

  perl definitely doesn't satisfy this one, or only in very pervert way.
the objects (any variables, not objects as in OO) can evaluate as
different things (e.g. scalar versus array context), even as nothing,
it's just that perl handles nothing better then C (it doesn't do
anything with nothing, because it knows what's allocated).

  the other thing is that often it is not evaluated at compile time...

> 2) a well-defined runtime error occurs (e.g., Java's
>ArrayBoundsException).

  or segfault? just kidding...

  is java type-safe? http://www.research.att.com/~vj/bug.html

  perl often does not give you any error message, it just does something
it consider OK to do...

> There are no other possibilities.
> 
> In this particular case, Perl chooses to use the memory allocation
> system to satisfy type safety (it creates a new T, initializes it, and
> returns it).  It's not the only possibility, though; Java would throw an
> exception in this case.  No allocation involved.

  you just wrote there are no other possibilites and then two lines
later you list another possiblity (what perl does).

  P

Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread Gary Turner
On Thu, 03 Jan 2002 17:34:00 -0600 (CST), Richard Cobbe wrote:
>
>Lo, on Thursday, January 3, Erik Steffl did write:
>
>> what's the difference? the point is you can assign almost anything to
>> anything, and yet there is no segfault - i.e. the strength of types has
>> nothing (sort of) to do with segfaults... the resource allocation is
>> crucial...
>
>Type safety (plus dynamic allocation) implies advanced memory
>management.  The converse is not true: you can slap Boehm's conservative
>GC onto a C++ program, but you can still get segmentation faults:
>
>char str[] = { 'b', 'a', 'd', ' ', 's', 't', 'r', 'i', 'n', 'g' };
>// note the lack of a terminating '\0'!
>cout << str;
>

>No allocation issues involved.  As Ben Collins pointed out elsewhere in
>this thread (bit of a tree-shaped thread, isn't it?), this won't
>necessarily cause a segfault, but it can.  It's also a violation of
>type-safety: cout expects a null-terminated string, and as far as the
>compiler is concerned, str fits this.  However, there's no runtime check
>in the output routine to verify that this is, in fact, the case.  Ooops.

Neophyte that I am, I feel like I'm bringing a knife to this gunfight.
This example looks to be a cheat, in that you've defined an array and
then treated it as a string (legal).  Had you defined a string, it would
be null terminated and index addressable.  In any normal array operation
wouldn't you be checking for array limits?  The fact that you *can*
screw up doesn't mean you have to.  This strikes me as falling under the
heading of programmer or logic error, just as is freeing the pointer
that another pointer points to.  If you are nesting pointers, don't you
create a means to track dependencies?  In a relatively low-level
language like c/c++, isn't the programmer responsible for code
integrity?
>
>Therefore, I claim that type safety is a more fundamental concept than
>resource mangement.
>
Is there a difference?  Again, my ignorance knowing no bounds.  Doesn't
the type define the required allocation?  And if typing is loose or
undefined doesn't allocation depend on ad hoc testing?  In the example
above, is it a type, or allocation error if the *programmer* decides to
access str[10]?  (If I counted right, that's the next byte after the
array bloc.)

This discussion has merit, not from the religious aspect of angels
dancing on pinheads, but rather will the pin hold my note on the cork
board?

gt
Yes I fear I am living beyond my mental means--Nash



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread Erik Steffl
Phil Beder wrote:
...
> I wish I was a good enough programmer to contribute to this great project.
> Maybe one day when I understand more about Linux I could write a more user
> friendly help interface with clear syntax, option, and flag usage.

  by that time you'll swear by man pages! :-))

erik



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread Daniel Freedman
On Thu, Jan 03, 2002, Phil Beder wrote:
> Thank you!!
> 
> The diversity of point of view and depth of knowledge of the participants
> of this group is truly phenomenal.  A simple question (in essence "where
> should I start") yielded me not only an interesting variety of response to
> that question, but a road map, complete with pitfalls and milestones and a
> vision of where I should end-up.  
> 
> Questions I would have never though to ask were answered, as the ping pong
> ball of opinion flew around.  Why use a low level language like "C" for GUI
> applications -vs.- why not when one language will do the trick.  The
> benefits of being able to allocate and access memory locations directly.
> Old standards -vs.- ANSI 99. Types, Classes,  Portablilty!!   . . .  WOW
> 
> I understand now why "C" was creating such a stir back in 1989 when I first
> started into programming.  It's abilities both as a low level and high
> level language are, I believe, what make it so universally accepted.  With
> "C" a programmer enjoys the flexibility to write a function many different
> ways, which means I don't think I would look forward to maintaining "C"
> code written by a bunch of programmers with diverse views (but I guess I
> sure would learn a lot).  
> 
> Thanks for your help, . . . all of you.  I'll be sure to avoid the rest of
> Herb Schildts books (I got a small inexpensive programmers reference of "C"
> keywords & functions and some common "C++" functions that has comes in
> handy for figuring-out usage and syntax).  After what you guys said, I‘ll
> bet his ears are ringing.  I haven't found the Kernighan and Ritchie book
> in my local bookstore. I have been using a "C for Linux" book which seems
> to get right to the point and I appreciate the direct application to Linux
> and the gcc compiler.

Hi,

No comments to add about the language wars, but as far as books go, I
find often the easiest method by which to determine what books are
worth looking at and what are junk, is by publisher.  I don't think
it's an anomoly that out of 30+ computer science books I have around,
almost all are published by O'Reilly, Addison Wesley, PTR/Prentice
Hall, John Wiley, and New Riders.  These publishers, IMHO, uniformlly
produce much higher quality CS/IT books than most others.  I've found
generally that Que, Sams, IDG/Hungry Minds, and others (I can't
remember right now) are significantly worse, and rarely even consider
them.  I suggest a similar strategy might prove useful to you as well.
I also recommend bookpool.com (standard no affiliation disclaimer) as
a great place to shop online, especially for price and customer
service.

HTH,

Daniel

> I wish I was a good enough programmer to contribute to this great project.
> Maybe one day when I understand more about Linux I could write a more user
> friendly help interface with clear syntax, option, and flag usage.
> 
> Thanks again
> 
> 
> -- 
> To UNSUBSCRIBE, email to [EMAIL PROTECTED] 
> with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]
> 

-- 
Daniel A. Freedman
Laboratory for Atomic and Solid State Physics
Department of Physics
Cornell University



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread Phil Beder
Thank you!!

The diversity of point of view and depth of knowledge of the participants
of this group is truly phenomenal.  A simple question (in essence "where
should I start") yielded me not only an interesting variety of response to
that question, but a road map, complete with pitfalls and milestones and a
vision of where I should end-up.  

Questions I would have never though to ask were answered, as the ping pong
ball of opinion flew around.  Why use a low level language like "C" for GUI
applications -vs.- why not when one language will do the trick.  The
benefits of being able to allocate and access memory locations directly.
Old standards -vs.- ANSI 99. Types, Classes,  Portablilty!!   . . .  WOW

I understand now why "C" was creating such a stir back in 1989 when I first
started into programming.  It's abilities both as a low level and high
level language are, I believe, what make it so universally accepted.  With
"C" a programmer enjoys the flexibility to write a function many different
ways, which means I don't think I would look forward to maintaining "C"
code written by a bunch of programmers with diverse views (but I guess I
sure would learn a lot).  

Thanks for your help, . . . all of you.  I'll be sure to avoid the rest of
Herb Schildts books (I got a small inexpensive programmers reference of "C"
keywords & functions and some common "C++" functions that has comes in
handy for figuring-out usage and syntax).  After what you guys said, I‘ll
bet his ears are ringing.  I haven't found the Kernighan and Ritchie book
in my local bookstore. I have been using a "C for Linux" book which seems
to get right to the point and I appreciate the direct application to Linux
and the gcc compiler.

I wish I was a good enough programmer to contribute to this great project.
Maybe one day when I understand more about Linux I could write a more user
friendly help interface with clear syntax, option, and flag usage.

Thanks again



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread Richard Cobbe
Lo, on Thursday, January 3, Erik Steffl did write:

> what's the difference? the point is you can assign almost anything to
> anything, and yet there is no segfault - i.e. the strength of types has
> nothing (sort of) to do with segfaults... the resource allocation is
> crucial...

Type safety (plus dynamic allocation) implies advanced memory
management.  The converse is not true: you can slap Boehm's conservative
GC onto a C++ program, but you can still get segmentation faults:

char str[] = { 'b', 'a', 'd', ' ', 's', 't', 'r', 'i', 'n', 'g' };
// note the lack of a terminating '\0'!
cout << str;

No allocation issues involved.  As Ben Collins pointed out elsewhere in
this thread (bit of a tree-shaped thread, isn't it?), this won't
necessarily cause a segfault, but it can.  It's also a violation of
type-safety: cout expects a null-terminated string, and as far as the
compiler is concerned, str fits this.  However, there's no runtime check
in the output routine to verify that this is, in fact, the case.  Ooops.

Therefore, I claim that type safety is a more fundamental concept than
resource mangement.

> that's all interesting, but the point was that the perl type system is
> as weak as I can imagine yet it doesn't lead to segfaults... it's the
> resource allocation!

Type safety != `strong' types.  They're orthogonal.  (Well, sort of.  It
turns out that `strong types' isn't a very well-defined concept;
language researchers prefer to discuss compile-time type verification.
*That* definitely has nothing to do with type safety.)
 
> If you cannot make sure that MyUserType variable will only be assigned
> MyUserType values then you have (almost) NO type safety.

That's only meaningful if you can declare a variable to be MyUserType at
runtime.  This does not apply to a whole variety of languages, many of
which are still type-safe.

(I think I'm just going to decide that Perl's type system is on crack.
But what do you expect when a linguist designs a programming language?)

> > In any case, memory allocation errors aren't the only cause of
> > segmentation faults---how about walking off the end of an array?  Here,
> > I claim that Perl *does* maintain type-safety, although in a seriously
> > fscked-up way: it simply expands the array to make the reference valid.
> 
>   it's not the types! it doesn't care about types at all. it just makes
> sure you always have a place to store whatever you are about to store.
> what does that have with types? not much. it has to know what are you
> trying to store but it doesn't care at all what was there before, what's
> the type of variable where you are storing it. again, I find it pretty
> strange to call that kind of behaviour 'type safety'.

Yes, it *is* types.  Remember the definition of type-safety:

If an expression E is determined at compile time to have type T,
then evaluating E will have one of two results:

1) The value of E is a valid object of type T and not just some
   random collection of bits we're misinterpreting as a T.
2) a well-defined runtime error occurs (e.g., Java's
   ArrayBoundsException).
There are no other possibilities.

In this particular case, Perl chooses to use the memory allocation
system to satisfy type safety (it creates a new T, initializes it, and
returns it).  It's not the only possibility, though; Java would throw an
exception in this case.  No allocation involved.

Richard



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread Erik Steffl
Richard Cobbe wrote:
> 
> Lo, on Thursday, January 3, William T Wilson did write:
> 
> > On Wed, 2 Jan 2002, Richard Cobbe wrote:
> >
> > > I'll agree that the two are related; in fact, I'd go so far as to say
> > > that if a language supports dynamic memory allocation and type-safety,
> > > it *has* to have some sort of automatic storage management system.
> >
> > I don't think that necessarily follows; a manual mechanism for freeing
> > resources would then just set the reference to a NULL value.
> 
> Not in the general case, no.
> 
> std::string *s = new string("foo");
> std::string *s2 = s;
> 
> delete s;
> 
> If we assume a variant of C++ that extends delete to set its argument
> pointer to NULL, you still have the problem of s2 hanging around.  In
> the general case, it's not so obvious that you've got two pointers to
> reset.

  unless, of course, you also keep track of who points to given piece of
memory ;-) whoops...

erik



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread Richard Cobbe
Lo, on Thursday, January 3, William T Wilson did write:

> On Wed, 2 Jan 2002, Richard Cobbe wrote:
> 
> > I'll agree that the two are related; in fact, I'd go so far as to say
> > that if a language supports dynamic memory allocation and type-safety,
> > it *has* to have some sort of automatic storage management system.
> 
> I don't think that necessarily follows; a manual mechanism for freeing
> resources would then just set the reference to a NULL value.

Not in the general case, no.

std::string *s = new string("foo");
std::string *s2 = s;

delete s;

If we assume a variant of C++ that extends delete to set its argument
pointer to NULL, you still have the problem of s2 hanging around.  In
the general case, it's not so obvious that you've got two pointers to
reset.



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread Craig Dickson
dman wrote:

> However the thing to remember about macros is that they are textual
> substituation.  It is effectively the same thing as writing the
> assignment yourself.

So? You could say the same of C++ templates, but that doesn't mean they
aren't useful. You can't even use the "code bloat" argument against
templates if your alternative is to write out all the instances by hand;
the result is the same, it just saves time and reduces errors to write
it once instead of once per type.

> inline functions are really no better than macros, and can even cause
> bugs (though surely that's just a sign of a buggy compiler).

I'm not that familiar with how inline is used in C, but in C++, it's
silly to say that inlines are no better than macros. Inlines are
type-safe, macros aren't; inlines can be members of a class or
namespace, macros can't. And you're right that any bugs resulting from
the "inline" keyword must result from bugs in the compiler, but that's
an argument against using buggy compilers, not an argument against
inlines.

> For a particular school project (C++ required) the profs had a working
> demo that we could run to verify our output (and clarify anything in
> the specs).  They compiled it without debug symbols so we couldn't
> look at it in a debugger and reverse-engineer it.  Their demo would
> crash with certain malformed input.  One of the profs tried to figure
> it out, but once it was recompiled with debug symbols (which also
> turns off inlining, for that compiler at least) the program worked
> correctly.  They had used inline functions extensively in their
> code.

Was this ever tracked down? There are probably other differences between
the debug and non-debug builds. Optimizations, perhaps?

Working in Win32 with Microsoft C++, I've several times had bugs that
only happened in non-debug builds. It's never been because of inlines,
though. Usually subtle timing issues, or a rogue pointer that in a debug
build was pointing at something harmless.

> There's no real point to an inline function, just make it a regular
> function.  The overhead of a function call isn't very big, especially
> nowadays.

The overhead is a lot less than it used to be (at least for the x86
family; I'm less familiar with others), but it's still non-zero, so it
still matters in performance-critical code.

I have always tended to inline trivial class/namespace members as a
matter of habit, because in some cases the inlining actually results in
smaller code than a regular function would (no parameter passing
overhead, and optimizations can be applied to the inlined code as if it
were part of the function that called it). As with performance, this
isn't usually all that big a deal these days, but it certainly doesn't
hurt.

Craig



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread dman
On Thu, Jan 03, 2002 at 07:04:38AM -0800, Eric G. Miller wrote:
| On Thu, 3 Jan 2002 09:31:16 -0500, dman <[EMAIL PROTECTED]> wrote:

| > However the thing to remember about macros is that they are textual
| > substituation.  It is effectively the same thing as writing the
| > assignment yourself.
| 
| Yes, but for a little block of code that you'd use often, you don't
| have to repeat it gadzillion times, and the result should be easier
| to read.

There are times when a macro is the best alternative, however it is
not part of the programing language itself.  (you can use macros in
java, if you run the source through a preprocessor before the java
compiler gets to it, in fact this is true of any textual data (ie
pipes and filters :-)))

| Problem is, these things can be abused.  Add a bunch of
| global data structs, and you've got a nearly impossible to maintain
| chunk of code...

Right.

| > | I've had occasion to use some replacement macros for malloc and realloc as
| > | well.  The realloc being the more useful.  Inline functions are
| > | cleaner though...
| > 
| > inline functions are really no better than macros, and can even cause
| > bugs (though surely that's just a sign of a buggy compiler).
| > 
| > For a particular school project (C++ required) the profs had a working
| > demo that we could run to verify our output (and clarify anything in
| > the specs).  They compiled it without debug symbols so we couldn't
| > look at it in a debugger and reverse-engineer it.  Their demo would
| > crash with certain malformed input.  One of the profs tried to figure
| > it out, but once it was recompiled with debug symbols (which also
| > turns off inlining, for that compiler at least) the program worked
| > correctly.  They had used inline functions extensively in their
| > code.
| 
| I think there are some subtle differences between inlining C++ and
| inlining C.  Since, I haven't done any C++ for a couple years, I
| was thinking in C.

IIRC C didn't have 'inline' until C99, though I think gcc implmented
it anyways.

| Well, can't say I've ever gotten into the habit of using "inline". 

Glad to hear that :-).

| It's just not portable enough in C

See above.

-D

-- 

A perverse man stirs up dissension,
and a gossip separates close friends.
Proverbs 16:28



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread Eric G . Miller
On Thu, 3 Jan 2002 09:31:16 -0500, dman <[EMAIL PROTECTED]> wrote:

[snip]
> | > If you wrote a wrapper around free() that took a pointer to a pointer
> | > you _could_ then assign NULL to the second pointer, but that, of
> | > course, assumes that inside free() you have a valid pointer to
> | > dereference in the first place.
> | 
> | A macro is easier (vile things that they are...)
> 
> Well, yeah, I was forgetting about them.
> 
> | #define FREE(p) {if(p){free(p); (p)=NULL;}}
> 
> However the thing to remember about macros is that they are textual
> substituation.  It is effectively the same thing as writing the
> assignment yourself.

Yes, but for a little block of code that you'd use often, you don't
have to repeat it gadzillion times, and the result should be easier
to read.  Problem is, these things can be abused.  Add a bunch of
global data structs, and you've got a nearly impossible to maintain
chunk of code...

> | I've had occasion to use some replacement macros for malloc and realloc as
> | well.  The realloc being the more useful.  Inline functions are
> | cleaner though...
> 
> inline functions are really no better than macros, and can even cause
> bugs (though surely that's just a sign of a buggy compiler).
> 
> For a particular school project (C++ required) the profs had a working
> demo that we could run to verify our output (and clarify anything in
> the specs).  They compiled it without debug symbols so we couldn't
> look at it in a debugger and reverse-engineer it.  Their demo would
> crash with certain malformed input.  One of the profs tried to figure
> it out, but once it was recompiled with debug symbols (which also
> turns off inlining, for that compiler at least) the program worked
> correctly.  They had used inline functions extensively in their
> code.

I think there are some subtle differences between inlining C++ and
inlining C.  Since, I haven't done any C++ for a couple years, I
was thinking in C.  Anyway, the type of bug you describe sounds
more like the kind of bugs that are real, but somehow you got away
with it until you switched compilers or turned on some optimizations.

> There's no real point to an inline function, just make it a regular
> function.  The overhead of a function call isn't very big, especially
> nowadays.

Well, can't say I've ever gotten into the habit of using "inline".  It's
just not portable enough in C, without going through a bunch of configure
feature tests and macro substitutions (when it's not recognized).  But I
expect it could make a substantial difference when the function in
question is often used in looping constructs.  But, you know what they
say about premature optimization...

-- 
Eric G. Miller 



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread dman
On Thu, Jan 03, 2002 at 05:01:50AM -0800, Eric G. Miller wrote:
| On Thu, 3 Jan 2002 07:22:59 -0500, dman <[EMAIL PROTECTED]> wrote:
| 
| > On Thu, Jan 03, 2002 at 12:19:25AM -0500, William T Wilson wrote:
| > | On Wed, 2 Jan 2002, Richard Cobbe wrote:
| > | 
| > | > I'll agree that the two are related; in fact, I'd go so far as to say
| > | > that if a language supports dynamic memory allocation and type-safety,
| > | > it *has* to have some sort of automatic storage management system.
| > | 
| > | I don't think that necessarily follows; a manual mechanism for freeing
| > | resources would then just set the reference to a NULL value.
| > 
| > Erm, no.  The function can't change the environment of its caller :
| > 
| > int main()
| > {
| > int* ptr ;
| > 
| > /* allocate some space */
| > ptr = malloc( 2*sizeof(int) ) ;
| > /* see where that space starts */
| > printf( "%d" , ptr ) ;
| > free( ptr ) ;
| > /* it still points there, but dereferencing the pointer now is bad */
| > printf( "%d" , ptr ) ;
| > return 1 ;
| > }
| > 
| > 
| > If you wrote a wrapper around free() that took a pointer to a pointer
| > you _could_ then assign NULL to the second pointer, but that, of
| > course, assumes that inside free() you have a valid pointer to
| > dereference in the first place.
| 
| A macro is easier (vile things that they are...)

Well, yeah, I was forgetting about them.

| #define FREE(p) {if(p){free(p); (p)=NULL;}}

However the thing to remember about macros is that they are textual
substituation.  It is effectively the same thing as writing the
assignment yourself.

| I've had occasion to use some replacement macros for malloc and realloc as
| well.  The realloc being the more useful.  Inline functions are
| cleaner though...

inline functions are really no better than macros, and can even cause
bugs (though surely that's just a sign of a buggy compiler).

For a particular school project (C++ required) the profs had a working
demo that we could run to verify our output (and clarify anything in
the specs).  They compiled it without debug symbols so we couldn't
look at it in a debugger and reverse-engineer it.  Their demo would
crash with certain malformed input.  One of the profs tried to figure
it out, but once it was recompiled with debug symbols (which also
turns off inlining, for that compiler at least) the program worked
correctly.  They had used inline functions extensively in their
code.

There's no real point to an inline function, just make it a regular
function.  The overhead of a function call isn't very big, especially
nowadays.

-D

-- 

A)bort, R)etry, B)ang it with a large hammer



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread Eric G . Miller
On Thu, 3 Jan 2002 07:22:59 -0500, dman <[EMAIL PROTECTED]> wrote:

> On Thu, Jan 03, 2002 at 12:19:25AM -0500, William T Wilson wrote:
> | On Wed, 2 Jan 2002, Richard Cobbe wrote:
> | 
> | > I'll agree that the two are related; in fact, I'd go so far as to say
> | > that if a language supports dynamic memory allocation and type-safety,
> | > it *has* to have some sort of automatic storage management system.
> | 
> | I don't think that necessarily follows; a manual mechanism for freeing
> | resources would then just set the reference to a NULL value.
> 
> Erm, no.  The function can't change the environment of its caller :
> 
> int main()
> {
> int* ptr ;
> 
> /* allocate some space */
> ptr = malloc( 2*sizeof(int) ) ;
> /* see where that space starts */
> printf( "%d" , ptr ) ;
> free( ptr ) ;
> /* it still points there, but dereferencing the pointer now is bad */
> printf( "%d" , ptr ) ;
> return 1 ;
> }
> 
> 
> If you wrote a wrapper around free() that took a pointer to a pointer
> you _could_ then assign NULL to the second pointer, but that, of
> course, assumes that inside free() you have a valid pointer to
> dereference in the first place.

A macro is easier (vile things that they are...)

#define FREE(p) {if(p){free(p); (p)=NULL;}}

I've had occasion to use some replacement macros for malloc and realloc as
well.  The realloc being the more useful.  Inline functions are cleaner 
though...

#define REALLOC(p, s, str)\
{if ((s) > 0)\
   {void *ptr = realloc (p, s);\
if (!ptr)\
   {fprintf(stderr,"realloc(%p,%d) failed in %s\n", p, s, str);\
exit (EXIT_FAILURE);\
   }\
else {(p) = ptr;}}
   }\
}

Course, the REALLOC doesn't improve safety one whit (just a convenience).

-- 
Eric G. Miller 



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread dman
On Thu, Jan 03, 2002 at 12:19:25AM -0500, William T Wilson wrote:
| On Wed, 2 Jan 2002, Richard Cobbe wrote:
| 
| > I'll agree that the two are related; in fact, I'd go so far as to say
| > that if a language supports dynamic memory allocation and type-safety,
| > it *has* to have some sort of automatic storage management system.
| 
| I don't think that necessarily follows; a manual mechanism for freeing
| resources would then just set the reference to a NULL value.

Erm, no.  The function can't change the environment of its caller :

int main()
{
int* ptr ;

/* allocate some space */
ptr = malloc( 2*sizeof(int) ) ;
/* see where that space starts */
printf( "%d" , ptr ) ;
free( ptr ) ;
/* it still points there, but dereferencing the pointer now is bad */
printf( "%d" , ptr ) ;
return 1 ;
}


If you wrote a wrapper around free() that took a pointer to a pointer
you _could_ then assign NULL to the second pointer, but that, of
course, assumes that inside free() you have a valid pointer to
dereference in the first place.

-D

-- 

Trust in the Lord with all your heart and lean not on your own
understanding; in all your ways acknowledge Him, and He will make your
paths straight.
Proverbs 3:5-6



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread dman
On Thu, Jan 03, 2002 at 01:33:29AM -0500, Michael P. Soulier wrote:
| On 02/01/02 Richard Cobbe did speaketh:
| 
| > > > Perl does have strong types, but they don't really correspond to the
| > > > types that most people are used to thinking of.  Perl's types are
| 
| Personally, I wouldn't call Perl strongly-typed at all. I code all day
| in Perl, and I love it, but I also know what a pain it can be for
| programming in the large, due to all those cool features that make
| coding a 1000 line script so easy. 
| 
| It's difficult to call any language that doesn't include types of
| return values to functions strongly typed, especially when the
| existing types are all automagickally casted based on context. Most
| perl errors show up at runtime, not compile time. 

Wrong -- this is called "dynamically" typed and is an independent
property from "statically" typed.  See a few days ago where I gave
some examples of
static  weak
static  strong
dynamic weak
dynamic strong
type systems.  Perl falls into the "dynamic weak" category.

Python is strongly typed but it too is dynamically typed.

| My biggest complaint? The dynamic binding means that you can call a
| subroutine that doesn't exist, and you won't find out about it until
| runtime, which may be a segment of code that executes once per
| year. Typos are hell. 

This is a tool problem, not a language problem.  This is one of the
main complaints people have about dynamic typing on comp.lang.python,
but the solution is to create a tool, not to change the language.  For
python someone created PyChecker that looks at your source and
attempts to spot the most common errors and report them to you.

-D

-- 

Through love and faithfulness sin is atoned for;
through the fear of the Lord a man avoids evil.
Proverbs 16:6



Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread Erik Steffl
Richard Cobbe wrote:
> 
> Lo, on Wednesday, January 2, Erik Steffl did write:
> 
> > Richard Cobbe wrote:
> > >
> > > Lo, on Monday, December 31, Erik Steffl did write:
> > >
> > > Perl does have strong types, but they don't really correspond to the
> > > types that most people are used to thinking of.  Perl's types are
> > >
> > > * scalars (no real distinction between strings, numbers, and the
> > >   undefined value)
> > > * lists
> > > * hashes
> > > * filehandles
> > >
> > > (I haven't really used Perl since Perl 4, so this list may not be
> > > complete.)
> >
> >   actually there is real distinction between string and number, it's
> > just that it's internal only (perl stores numbers and strings
> > differently, it also treats them differently).
> 
> Since Perl automatically converts between strings and numbers whenever
> it feels like it, there's really no important distinction between the

  ???

  what's the difference? the point is you can assign almost anything to
anything, and yet there is no segfault - i.e. the strength of types has
nothing (sort of) to do with segfaults... the resource allocation is
crucial...

> two from the programmer's perspective.  (In other words: since you can't
> tell if a Perl scalar contains the number 33 or the string '33', there's
> no practical difference between the types.)  Implementation details are
> really pretty irrelevant at the level at which I'm discussing the
> language.

  well, mostly...

> >   the point was that it's not a strong type system - by which I mean
> > that you can assign pretty much any value to any l-value, no questions
> > asked. You don't get segfault but you still get non-working program
> > (e.g. when you mistakenly assing array to scalar, you get size of array
> > in scalar).
> 
> Oh, right.  I'd forgotten about the whole scalar/array context thing.
> (You can tell that I don't use Perl that often, yes?)  Since, however,
> the following two statements aren't inverses
> $bar = @foo;
> @foo = $bar;
> (the latter sets @foo's length, does it not?) I'd be tempted to explain
> the list-to-scalar conversion in terms of an implicit conversion, much
> like those performed by C++ in the presence of, say, single-argument
> constructors.
> 
> Even if that doesn't work, though, then you can take the LISP tactic,
> and just consider everything to be the same (static) type:
> ThePerlDataType.  This type has several variants for scalars, lists,
> references, and so forth.

  that's all interesting, but the point was that the perl type system is
as weak as I can imagine yet it doesn't lead to segfaults... it's the
resource allocation!

> >   the reason you don't get segfaults is that perl takes care of memory
> > allocation, e.g. if you try to assign something to the variable that's
> > undefined (no storage place yet), it allocates appropriate amount of
> > memory or if you try to read a value of variable that doesn't have value
> > it says that undefined variable was used (doesn't give you random piece
> > of memory like you can get in c).
> >
> > > > most of the segfaults are because of the resource allocation mistakes,
> > > > not because of mistaken types... at last that's my impression.
> > >
> > > Resource allocation mistakes (at least, the kind that typically lead to
> > > seg faults) *are* type errors, from a certain point of view.
> >
> > when you stretch it far enough.
> 
> It's not a stretch at all; it simply requires thinking about types in a
> way not very common among C/C++/Java programmers.
> 
> >   generally there are two distinct problems: [resource allocation
> >   errors and type errors]
> 
> I'll agree that the two are related; in fact, I'd go so far as to say
> that if a language supports dynamic memory allocation and type-safety,
> it *has* to have some sort of automatic storage management system.
> Otherwise, you can delete objects too early and cause problems.  My
> original point, though, was that early deletions like this actually
> short-circuit the type system, since they break the type-safety
> invariant.

  that's true, to certain extend.

> >   IMO it's good to have clear distinction between resource allocation
> > and type safety. example of perl - it doesn't have type safety, it lets
> > you assing (almost) anything to anything but you still don't get
> > problems as you describe above because it handles the memory allocation
> > automatically.
> 
> Perl's a little weird, I'll grant you, but the fact that you can do this
> sort of `free assignment' doesn't preclude typesafety.  Ferinstance, in
> Scheme, I can do this without any problems:
> 
> (define x 3);; variable definition & declaration
> (set! x "three");; variable assignment
> 
> Works just fine.  Of course, if I then try to add x to 4 after the set!,
> I'll get a run-time error---thus type-safety.

  in this case yes, in other cases, no. I can't speak of lisp but in
perl it's definitely not what I would call type safety

Re: OT: Language War (Re: "C" Manual)

2002-01-03 Thread Michael P. Soulier
On 02/01/02 Richard Cobbe did speaketh:

> > > Perl does have strong types, but they don't really correspond to the
> > > types that most people are used to thinking of.  Perl's types are

Personally, I wouldn't call Perl strongly-typed at all. I code all day
in Perl, and I love it, but I also know what a pain it can be for
programming in the large, due to all those cool features that make
coding a 1000 line script so easy. 

It's difficult to call any language that doesn't include types of
return values to functions strongly typed, especially when the
existing types are all automagickally casted based on context. Most
perl errors show up at runtime, not compile time. 

My biggest complaint? The dynamic binding means that you can call a
subroutine that doesn't exist, and you won't find out about it until
runtime, which may be a segment of code that executes once per
year. Typos are hell. 

Mike

-- 
Michael P. Soulier <[EMAIL PROTECTED]>, GnuPG pub key: 5BC8BE08
"...the word HACK is used as a verb to indicate a massive amount
of nerd-like effort."  -Harley Hahn, A Student's Guide to Unix


pgp9WVcMpn2DT.pgp
Description: PGP signature


Re: OT: Language War (Re: "C" Manual)

2002-01-02 Thread William T Wilson
On Wed, 2 Jan 2002, Richard Cobbe wrote:

> I'll agree that the two are related; in fact, I'd go so far as to say
> that if a language supports dynamic memory allocation and type-safety,
> it *has* to have some sort of automatic storage management system.

I don't think that necessarily follows; a manual mechanism for freeing
resources would then just set the reference to a NULL value.

But I think that most strongly typed languages do have automatic resource
management of some sort, because it is so useful :}



Re: OT: Language War (Re: "C" Manual)

2002-01-02 Thread Richard Cobbe
Lo, on Wednesday, January 2, Erik Steffl did write:

> Richard Cobbe wrote:
> > 
> > Lo, on Monday, December 31, Erik Steffl did write:
> > 
> > Perl does have strong types, but they don't really correspond to the
> > types that most people are used to thinking of.  Perl's types are
> > 
> > * scalars (no real distinction between strings, numbers, and the
> >   undefined value)
> > * lists
> > * hashes
> > * filehandles
> > 
> > (I haven't really used Perl since Perl 4, so this list may not be
> > complete.)
> 
>   actually there is real distinction between string and number, it's
> just that it's internal only (perl stores numbers and strings
> differently, it also treats them differently).

Since Perl automatically converts between strings and numbers whenever
it feels like it, there's really no important distinction between the
two from the programmer's perspective.  (In other words: since you can't
tell if a Perl scalar contains the number 33 or the string '33', there's
no practical difference between the types.)  Implementation details are
really pretty irrelevant at the level at which I'm discussing the
language.

>   the point was that it's not a strong type system - by which I mean
> that you can assign pretty much any value to any l-value, no questions
> asked. You don't get segfault but you still get non-working program
> (e.g. when you mistakenly assing array to scalar, you get size of array
> in scalar).

Oh, right.  I'd forgotten about the whole scalar/array context thing.
(You can tell that I don't use Perl that often, yes?)  Since, however,
the following two statements aren't inverses
$bar = @foo;
@foo = $bar;
(the latter sets @foo's length, does it not?) I'd be tempted to explain
the list-to-scalar conversion in terms of an implicit conversion, much
like those performed by C++ in the presence of, say, single-argument
constructors.

Even if that doesn't work, though, then you can take the LISP tactic,
and just consider everything to be the same (static) type:
ThePerlDataType.  This type has several variants for scalars, lists,
references, and so forth.

>   the reason you don't get segfaults is that perl takes care of memory
> allocation, e.g. if you try to assign something to the variable that's
> undefined (no storage place yet), it allocates appropriate amount of
> memory or if you try to read a value of variable that doesn't have value
> it says that undefined variable was used (doesn't give you random piece
> of memory like you can get in c).
> 
> > > most of the segfaults are because of the resource allocation mistakes,
> > > not because of mistaken types... at last that's my impression.
> > 
> > Resource allocation mistakes (at least, the kind that typically lead to
> > seg faults) *are* type errors, from a certain point of view.
> 
> when you stretch it far enough.

It's not a stretch at all; it simply requires thinking about types in a
way not very common among C/C++/Java programmers.

>   generally there are two distinct problems: [resource allocation
>   errors and type errors]

I'll agree that the two are related; in fact, I'd go so far as to say
that if a language supports dynamic memory allocation and type-safety,
it *has* to have some sort of automatic storage management system.
Otherwise, you can delete objects too early and cause problems.  My
original point, though, was that early deletions like this actually
short-circuit the type system, since they break the type-safety
invariant.

>   IMO it's good to have clear distinction between resource allocation
> and type safety. example of perl - it doesn't have type safety, it lets
> you assing (almost) anything to anything but you still don't get
> problems as you describe above because it handles the memory allocation
> automatically.

Perl's a little weird, I'll grant you, but the fact that you can do this
sort of `free assignment' doesn't preclude typesafety.  Ferinstance, in
Scheme, I can do this without any problems:

(define x 3);; variable definition & declaration
(set! x "three");; variable assignment

Works just fine.  Of course, if I then try to add x to 4 after the set!,
I'll get a run-time error---thus type-safety.

In any case, memory allocation errors aren't the only cause of
segmentation faults---how about walking off the end of an array?  Here,
I claim that Perl *does* maintain type-safety, although in a seriously
fscked-up way: it simply expands the array to make the reference valid.

> > Performing run-time checks, as with array indexing, does not necessarily
> > imply the existence of an interpreter.  If a compiler sees the
> > expression a[i], it can either assume that i's value is a valid index
> > for the array a (as C and C++ do), or it can insert the appropriate
> > checks directly into the executable code.  I still claim this is part of
> > the language's run-time system, regardless of how it's interpreted.
 

Re: OT: Language War (Re: "C" Manual)

2002-01-02 Thread Richard Cobbe
Lo, on Wednesday, January 2, Ben Collins did write:

> Just because in C it can cause a segfault doesn't mean the other
> languages are any better.

No, it doesn't.  However, IMNSHO, the fact that C and C++ have many
*more* undefined constructs that other languages does mean that the
other languages are better (in most situations).

> Show me one language that doesn't have some action that is classified
> as undefined.

I'm not aware of any, although PLT Scheme (http://www.plt-scheme.org/)
comes pretty close.  So what?  I never claimed that other languages are
completely defined; I simply said that the construct I mentioned
up-thread has undefined behavior in C and C++, and that this lack of
definition is dangerous.  (The few places where PLT Scheme's behavior is
undefined are also dangerous, but they arise much less
frequently---when's the last time you tried to invoke a continuation
from within one of dynamic-wind's guard thunks?)

> Documenting that something is undefined is called a specification.

Yes, in one sense, you're right.  But it's a pretty useless
specification.  `We specify that we do not specify what this construct
does.'  I don't see how this is supposed to be helpful.  If I had a
compiler that flagged all undefined constructs at compile-time so that I
didn't make them through careless errors, that would be one thing.
Unfortunately, that's not possible, because you can't *detect* all of
C's undefined constructs at compile-time.

> It is there so you know that you cannot rely on certain behavior. If
> you ignore that, then no language is going to help you.

Look, I'm not trying to ignore the fact that the ANSI/ISO C spec marks
certain constructs as undefined.  I'm saying that the fact that they are
undefined is not acceptable, especially when other languages
specifically define the behavior of the analogous constructs.  The fact
that the behavior of these constructions is completely specified by the
language means that I catch errors much earlier, whereas with C, I may
not catch them at all.  

The main issue: I'm tired of getting bogus output with no indication
that it's bogus, and I'm tired of spending long hours tracking down
silly pointer bugs that aren't an issue in more sophisticated languages.
The more undefined constructs in my language, the more time I have to
spend doing this kind of grunt work.  It's not that I want the computer
to do my entire job for me, but I would like it to do some of the grunt
work so I can concentrate on the interesting, challenging, and above all
*useful* parts of the program.

Richard



Re: OT: Language War (Re: "C" Manual)

2002-01-02 Thread Ben Collins
On Tue, Jan 01, 2002 at 09:44:17PM -0600, Richard Cobbe wrote:
> 
> Lo, on Tuesday, January 1, Ben Collins did write:
> 
> > On Tue, Jan 01, 2002 at 10:12:09AM -0600, Richard Cobbe wrote:
> > > 
> > > > Secondly, you can make this mistake with any language that allows
> > > > references (perl, python, and java all allow it). Just replace free()
> > > > with some other assignment that changes what a is, and ultimately you
> > > > change b, which referenced it, unintentionally.
> > > 
> > > True.  That, however, is not a type error of the sort that I'm
> > > describing.  And, in any case, the behavior of the program in that
> > > situation is well-defined by the language specification.  This is *not*
> > > the case with C or C++.
> > 
> > Of course it is defined. It says that after you free() an allocation,
> > that the memory the pointer references is gone and using the pointer
> > afterwards is undefined.
> 
> No, the program's behavior is *NOT* defined.  If it were defined, you
> would be able to predict the exact output of the program.  Saying that
> the standard specifically marks the program as having undefined behavior
> does not count as defining its behavior.

Every programming language has behaviors that are undefined. Just
because in C it can cause a segfault doesn't mean the other languages
are any better. Show me one language that doesn't have some action that
is classified as undefined.

Documenting that something is undefined is called a specification. It is
there so you know that you cannot rely on certain behavior. If you
ignore that, then no language is going to help you.

-- 
 .--===-=-==-=---==-=-.
/   Ben Collins--Debian GNU/Linux  \
`  [EMAIL PROTECTED]  --  [EMAIL PROTECTED]  --  [EMAIL PROTECTED]  '
 `---=--===-=-=-=-===-==---=--=---'



Re: OT: Language War (Re: "C" Manual)

2002-01-02 Thread Nori Heikkinen
on Wed, 02 Jan 2002 12:43:56AM -0800, Erik Steffl insinuated:
> Richard Cobbe wrote:
> > 
> > Perl does have strong types, but they don't really correspond to the
> > types that most people are used to thinking of.  Perl's types are
> > 
> > * scalars (no real distinction between strings, numbers, and the
> >   undefined value)
> > * lists
> > * hashes
> > * filehandles
> > 
> > (I haven't really used Perl since Perl 4, so this list may not be
> > complete.)
> 
>   actually there is real distinction between string and number, it's
> just that it's internal only (perl stores numbers and strings
> differently, it also treats them differently).
> 
[...]
> 
>   the point was that it's not a strong type system - by which I mean
> that you can assign pretty much any value to any l-value, no questions
> asked. You don't get segfault but you still get non-working program
> (e.g. when you mistakenly assing array to scalar, you get size of array
> in scalar).

agreed -- and not only that, but you have to be careful to be aware of
which type you're using in order to compare scalars and have it mean
anything -- numerical operators being the standard ==, !=, &c.;
whereas the equivalent string operators are 'eq', 'ne', &c.  it still
doesn't segfault (which is beautiful, and was the point here, i know),
but it makes your program more non-functional than if it just treated
the values the same.



<[EMAIL PROTECTED]>--
-http://www.sccs.swarthmore.edu/~nori/jnl/daily.html



Re: OT: Language War (Re: "C" Manual)

2002-01-02 Thread Erik Steffl
William T Wilson wrote:
> 
> On Mon, 31 Dec 2001, Erik Steffl wrote:
> 
> >   consider perl which doesn't have strong types but it's quite
> > impossible to make it segfault and C++ on the other side which is
> 
> That is true but it doesn't mean that type safety won't prevent it
> also.  Consider a hypothetical language that doesn't have any dynamic
> resource allocation at all and has a very weak type system.  Actually a
> shell scripting language is not very far from this.  It can never segfault
> although it is still possible to have the same sort of bugs which cause
> segfaults.

  are you trying to say same thing I said or are you saying the
opposite?

> > fairly dangerous even without casting (I would even go as far as
> > saying that casting makes no difference (statistally), but I'd have to
> > think about it).
> 
> The presence of casting doesn't have too much of an impact on the
> reliability of a particular program (if anything it improves it because it
> means the programmer thought about what his data really meant) but a
> language that doesn't keep track of the type of its data on the
> programmer's behalf cannot detect many errors at compile-time.

  wrong cast can lead to segfault, even if you'd use GC.

  well, see perl. doesn't care about your types and still doesn't
segfault.

> It can make sure that the programmer doesn't try to access a field that
> isn't present in the type of data that the pointer is supposed to
> represent, but it can't make sure that the pointer actually points to that
> sort of data.
> 
> The ability to check that the pointer points to the right type of data
> catches both a huge number of nuisance bugs *and* detects many types of
> segfaulting bugs even at compile time (and provides useful error
> descriptions even if it slips through to runtime).

  providing you have pointers. again, compare perl and c++ - c++ has
fairly strong (not really strong) types and yet you can make it segfault
easily. perl doesn't care about types much but it doesn't segfault (of
course, it has to keep track of types internally but that's mostly
hidden from progammer).

> Programmers that haven't used a really strongly typed language may not
> even even realize that the compiler is able to catch these sorts of bugs.

  perhaps...

> >   most of the segfaults are because of the resource allocation
> > mistakes, not because of mistaken types... at last that's my
> > impression.
> 
> In a lot of ways they are the same thing.  Suppose you have a pointer to
> an integer, and you change it so it points to a dynamically allocated
> array of pointers to integers (i.e. a 2-dimensional array) - which is
> perfectly legal in C - and then you free() the pointer.  Is this a
> resource allocation mistake or a type mistake?  It's really a resource
> allocation mistake, but it's also a type mistake, and it's something that
> a compiler in a strongly typed language would catch.

  a man was very poor. hungry all the time. finally got to hospital
emergency room with severe case of malnutrition.

  you can say it's both economic problem and nutrion problem, but I
guess you would admit that economics and nutrition are separate
disciplines and that generally problems can be solved as economic
problems or nutrition problems...

  don't mix the two. it just spoils the whole picture. the type problem
and the resource allocation problem are two separate problems, each can
be solved by different means.

> >   note that in c++ there's basically no need for casting and using
> > void pointers (in general, there are special cases). That's of course,
> 
> Casting you can't really get away from nor do you really need to.  In fact
> the more strongly typed the language is, the more casting you have to do.
> 
> (void) pointers on the other hand are generally not your friend :}

  why wouldn't you get away from casting? requiring casting is usually a
design problem (in java it's language design problem, but it's getting
templates soon:-)

  you might require casts in c for certain tasks...

erik



Re: OT: Language War (Re: "C" Manual)

2002-01-02 Thread Erik Steffl
Richard Cobbe wrote:
> 
> Lo, on Monday, December 31, Erik Steffl did write:
> 
> > "Eric G. Miller" wrote:
> > >
> > > On Mon, 31 Dec 2001 13:46:15 -0800, Erik Steffl <[EMAIL PROTECTED]> ...
> > > > it's the resource allocation that's important, not types. garbage
> > > > collectors are generally more robust as far as segfaulting (and
> > > > similar errors) go (of course, just because the program doesn't
> > > > segfault it doen't mean it's working correctly). the other
> > > > important factor is how much runtime check language does
> > > > (e.g. checking for array boundaries etc.)
> > >
> > > But it's the type safety of the language that prevents the abuse of
> > > memory, not how it was allocated.  Strong typing eliminates a huge
> > > number of error cases.  C and C++ both subvert the ability of the
> > > compiler to do static type checking via casts and void pointers.
> > > Strong static type checking also has the possible advantage that the
> > > compiler can better optimize the generated code.
> >
> > consider perl which doesn't have strong types but it's quite
> > impossible to make it segfault and C++ on the other side which is
> > fairly dangerous even without casting (I would even go as far as
> > saying that casting makes no difference (statistally), but I'd have to
> > think about it).
> 
> Perl does have strong types, but they don't really correspond to the
> types that most people are used to thinking of.  Perl's types are
> 
> * scalars (no real distinction between strings, numbers, and the
>   undefined value)
> * lists
> * hashes
> * filehandles
> 
> (I haven't really used Perl since Perl 4, so this list may not be
> complete.)

  actually there is real distinction between string and number, it's
just that it's internal only (perl stores numbers and strings
differently, it also treats them differently).

  it also has references and it knows what kind of references they are
(and since references are used to implement objects it even knows the
type of reference (what it was blessed into, plus whether it's scalar,
array, hash).

  the point was that it's not a strong type system - by which I mean
that you can assign pretty much any value to any l-value, no questions
asked. You don't get segfault but you still get non-working program
(e.g. when you mistakenly assing array to scalar, you get size of array
in scalar).

  the reason you don't get segfaults is that perl takes care of memory
allocation, e.g. if you try to assign something to the variable that's
undefined (no storage place yet), it allocates appropriate amount of
memory or if you try to read a value of variable that doesn't have value
it says that undefined variable was used (doesn't give you random piece
of memory like you can get in c).

> > most of the segfaults are because of the resource allocation mistakes,
> > not because of mistaken types... at last that's my impression.
> 
> Resource allocation mistakes (at least, the kind that typically lead to
> seg faults) *are* type errors, from a certain point of view.

  when you stretch it far enough.

  generally there are two distinct problems:

  1. resource allocation error:

  you use resource after it was freed
  you use resouce that was never allocated

  e.g.

  char *string;
  strcpy("should segfault", string);

  2. wrong type used:

  char c;
  int *i = (int*)(&c);
  *i = 12345; /* BOOM! */

  the first case COULD be described as type problem as well, if you say
that the compiler should check what the string actually points to but
it's not really the basic problem. just like the second problem can be
described as allocation problem (not enough space allocated for value of
i) but it would miss the point...

> Consider the following:
> 
> char *a, *b;
> 
> a = strdup("This is a sample string");
> b = a;
> 
> free(a);
> 
> /* Much code follows here, none of which modifies b. */
> 
> printf("%s\n", b);
> 
> This may or may not segfault, but it's obviously not correct.  The
> problem is, in fact, a type error in the reference to b in the printf()
> call.  The compiler and library think that b is a pointer to a
> null-terminated character string, but this is in fact not the case.  In
> a type-safe language, you would not be allowed to bring about this state
> of affairs.

  IMO it's good to have clear distinction between resource allocation
and type safety. example of perl - it doesn't have type safety, it lets
you assing (almost) anything to anything but you still don't get
problems as you describe above because it handles the memory allocation
automatically.

> > also note that in java you have to cast (when getting items from
> > containers) but it doesn't make java programs more likely to segfault.
> 
> That's because Java's typecasts are safe (i.e., checked at run-time):
> they're equivalent to C++'s dynamic_cast, not static_cast.  (Casting a
> float to an int, of course, is equivalent to C++'s static_cast, but
> errors with t

Re: OT: Language War (Re: "C" Manual)

2002-01-01 Thread dman
On Tue, Jan 01, 2002 at 09:39:18PM -0600, Richard Cobbe wrote:
| Lo, on Tuesday, January 1, dman did write:
| 
| > On Tue, Jan 01, 2002 at 10:34:25AM -0600, Richard Cobbe wrote:
| > | Lo, on Tuesday, January 1, dman did write:
| > | 
| > | > The strength and staticness of typing are two independent properties.
| > | 
| > | Also agreed.
| > 
| > Cool, I'm glad you know this stuff too!
| 
| Oh yeah.  I've got *way* too much Scheme/LISP experience to think that
| static typing and `strong' typing are the same thing.

:-).

| > |   2) downcasts in a class hierarchy, as in Java.  (Note that `upcasts'
| > |  aren't really casts: if B is a subclass of A, then an instance of B
| > |  *is* an instance of A, no cast needed.)
| > 
| > This is only needed with unintelligent compiler.  *You* know you have
| > a B at runtime, but the compiler doesn't so it whines and complains.
| > Thus you must "cast" the pointer/reference to appease the compiler.
| > The cast in java doesn't do anything else (aside from a runtime
| > verification as well)[1].
| 
| Well, in some cases, a sufficiently sophisticated compiler could
| determine at compile time that what it thinks is an A will, in fact,
| always be a B, thus removing the need for a downcast.  However, I don't
| think this sort of proof is possible in the general case.

I think this is what Haskell compilers do.

| And you're quite right, the downcast simply appeases the compiler by
| telling it, `No, this really is a B.'  The important thing is that you
| have the runtime check to verify this.  Without that, nasty things
| happen.
 
| > |  [Downcasts] are, however, useful in some situations, so (I
| > |  believe) many advanced languages with a static type system support
| > |  these.  However, as in Java, there's a run-time check that goes
| > |  with it.  C++'s dynamic_cast gets this right.
| > 
| > Take CORBA for example.  With python, you just have an object with the
| > given methods.  No problem, no difficulty.  
| 
| I've not worked with Python very much.

You're missing out on the fun.  With your Lisp/Scheme background you
will like the fact that python has built-in lists and has some
functions (map, reduce, filter) to work with them in a functional
style.

| Does it do compile-time type analysis like C++ or Java?

No.  It is completely runtime checked.

| I know that if there were CORBA bindings for a language like LISP or
| Scheme, you wouldn't have to worry about casts---the methods you
| expect are automatically there.  Presumably the same applies to
| Smalltalk, but I'm not sure.

This is how python works for all objects, not just CORBA.  You simply
use it the way you want to (based on what you expect the type to be)
and, of course, document that as a precondition for the function.  If
you need a file-like object, state that, and it is the client's
responsibility to provide one.  The beauty of it is (1) no time is
spent telling the compiler what you have and (2) polymorphism is
achieved without requiring inheritance (of classes or interfaces).

The python-orbit package contains python bindings for ORBit.  This
particular binding doesn't have any IDL compiler program.  When you
load it (import the module) it hooks itself into the import mechanism.
If it finds an idl file that matches the module you (later on) try to
import it will parse it then and create the necessary classes.  You
_know_ the classes are there and you know the methods are there
because they are (you wrote the IDL or someone else did and you read
it).  It is really convenient and a time saver!

| > With java you have to use a special "narrow" method to create an
| > instance of a class that implements the interface, but does so in
| > terms of corba calls.  With the inflexible type system java uses, the
| > downcast-wannabe is necessary (ugh!).
| 
| This is one instance, I believe, where there's a very visible tradeoff
| between the flexibility of run-time typechecks and the early error
| detection provided by compile-time typechecks.  Let's take OCaml
| (another language that I'm really not all *that* familiar with).  It has
| an object system and checks types at compile time, but it also has a
| much more flexible type system than Java's.  Instead of saying than an
| object is of type Foo, you instead say that the object has type
| < a : int -> int, b : ('a -> bool) -> 'a list, ... >
| which means that the object has *at least* methods a and b, and that a
| and b have the indicated types.

Yeah, this is like specifying (part of) the interface the type must
conform too.  It is much more flexible because it does not specify the
type (class) but just a piece of the interface.

| However, if you know full well that the object in question *also* has a
| method c (of whatever type), you won't be able to invoke it, because the
| compiler hasn't been able to prove that the object will always have such
| a method.  I would imagine there's some sort of checked downcast
| opera

Re: OT: Language War (Re: "C" Manual)

2002-01-01 Thread Richard Cobbe
Lo, on Tuesday, January 1, Ben Collins did write:

> On Tue, Jan 01, 2002 at 10:12:09AM -0600, Richard Cobbe wrote:
> > 
> > > Secondly, you can make this mistake with any language that allows
> > > references (perl, python, and java all allow it). Just replace free()
> > > with some other assignment that changes what a is, and ultimately you
> > > change b, which referenced it, unintentionally.
> > 
> > True.  That, however, is not a type error of the sort that I'm
> > describing.  And, in any case, the behavior of the program in that
> > situation is well-defined by the language specification.  This is *not*
> > the case with C or C++.
> 
> Of course it is defined. It says that after you free() an allocation,
> that the memory the pointer references is gone and using the pointer
> afterwards is undefined.

No, the program's behavior is *NOT* defined.  If it were defined, you
would be able to predict the exact output of the program.  Saying that
the standard specifically marks the program as having undefined behavior
does not count as defining its behavior.

In the alternative that you suggest (some assignment which changes a
rather than deleting it), the program's output *is* predictable.  You're
going to get a string printed out, and this string will appear as a
string literal in the program's source or be constructed by the program
during execution.  The important thing is that it will have been
constructed as a string and not be some random sequence of bytes.
Predicting the exact string that is printed may require some effort, but
(assuming the absence of pseudo-random number generators and assuming
that you know the program's full input) it is possible.

Richard



Re: OT: Language War (Re: "C" Manual)

2002-01-01 Thread Richard Cobbe
Lo, on Tuesday, January 1, dman did write:

> On Tue, Jan 01, 2002 at 10:34:25AM -0600, Richard Cobbe wrote:
> | Lo, on Tuesday, January 1, dman did write:
> | 
> | > The strength and staticness of typing are two independent properties.
> | 
> | Also agreed.
> 
> Cool, I'm glad you know this stuff too!

Oh yeah.  I've got *way* too much Scheme/LISP experience to think that
static typing and `strong' typing are the same thing.

> |   2) downcasts in a class hierarchy, as in Java.  (Note that `upcasts'
> |  aren't really casts: if B is a subclass of A, then an instance of B
> |  *is* an instance of A, no cast needed.)
> 
> This is only needed with unintelligent compiler.  *You* know you have
> a B at runtime, but the compiler doesn't so it whines and complains.
> Thus you must "cast" the pointer/reference to appease the compiler.
> The cast in java doesn't do anything else (aside from a runtime
> verification as well)[1].

Well, in some cases, a sufficiently sophisticated compiler could
determine at compile time that what it thinks is an A will, in fact,
always be a B, thus removing the need for a downcast.  However, I don't
think this sort of proof is possible in the general case.

And you're quite right, the downcast simply appeases the compiler by
telling it, `No, this really is a B.'  The important thing is that you
have the runtime check to verify this.  Without that, nasty things
happen.

> [1] with "primitive" types, I think java may do some conversion
> (certainly with float->int it must), but I'm not totally sure (I
> think with int->byte it doesn't, just truncates)

Yes, Java's casts between primitive types are conversions (as are C's).
Those aren't downcasts, though, as there's no type hierarchy involved
(it is not the case that an int IS-A byte, even though an int can
represent all possible values that a byte can).

> |  [Downcasts] are, however, useful in some situations, so (I
> |  believe) many advanced languages with a static type system support
> |  these.  However, as in Java, there's a run-time check that goes
> |  with it.  C++'s dynamic_cast gets this right.
> 
> Take CORBA for example.  With python, you just have an object with the
> given methods.  No problem, no difficulty.  

I've not worked with Python very much.  Does it do compile-time type
analysis like C++ or Java?  I know that if there were CORBA bindings for
a language like LISP or Scheme, you wouldn't have to worry about
casts---the methods you expect are automatically there.  Presumably the
same applies to Smalltalk, but I'm not sure.

> With java you have to use a special "narrow" method to create an
> instance of a class that implements the interface, but does so in
> terms of corba calls.  With the inflexible type system java uses, the
> downcast-wannabe is necessary (ugh!).

This is one instance, I believe, where there's a very visible tradeoff
between the flexibility of run-time typechecks and the early error
detection provided by compile-time typechecks.  Let's take OCaml
(another language that I'm really not all *that* familiar with).  It has
an object system and checks types at compile time, but it also has a
much more flexible type system than Java's.  Instead of saying than an
object is of type Foo, you instead say that the object has type
< a : int -> int, b : ('a -> bool) -> 'a list, ... >
which means that the object has *at least* methods a and b, and that a
and b have the indicated types.

However, if you know full well that the object in question *also* has a
method c (of whatever type), you won't be able to invoke it, because the
compiler hasn't been able to prove that the object will always have such
a method.  I would imagine there's some sort of checked downcast
operation to handle this situation.

In short: downcasts are perfectly safe if and only if there's a runtime
check involved.  

> | template
> | void register_callback(void (* cb)(T), T data);
> 
> That's not so bad, if you can stand the bloat this creates (C++
> templates are expanded at compile time, thus you get one copy of this
> function for each type it needs to work with).

Mph.  Don't write off polymorphism (which is what C++ templates
approximate) just because most C++ compilers do a really bad job of
implementing it.  It's a useful concept, and there are better strategies
out there; ML compilers tend to use these instead.  (To be fair, these
strategies have their own costs associated with them, but the code size
doesn't go through the roof.)

(Note, btw, that in the previous paragraph, `polymorphism' does NOT
refer to the OO concept.)

Richard



Re: OT: Language War (Re: "C" Manual)

2002-01-01 Thread David Teague
William, Richard, and all:

Stroustrup has said that if you find you have to cast, (much) your
design is flawed.

--David Teague



On Tue, 1 Jan 2002, William T Wilson wrote:

> On Tue, 1 Jan 2002, Richard Cobbe wrote:
> 
> > > | Casting you can't really get away from nor do you really need to.  In 
> > > fact
> > > | the more strongly typed the language is, the more casting you have to 
> > > do.
> > > 
> > > This statement is incorrect.
> > 
> > Agreed.
> 
> I suppose I will agree as well, I was not meaning to include dynamically
> typed languages in the original statement, I just didn't say that :}
> Really it was not a very good statement to make, although in the original
> context it wasn't so bad :}
> 
> > However, I think that the flexibility of a type system is more
> > important than its `strength' for removing the need for casts.
> 
> I will go along with that as well.  In ML for instance (and other
> languages as well) there is parametric polymorphism which give you a lot
> of the flexibility of dynamic typing while still retaining much of the
> error checking of static typing.  This is different from the
> "polymorphism" found in C++ in which you can have virtual functions (which
> still require the programmer to provide all the different implementations)
> and inheritance (which only permits polymorphism within a very limited set
> of types).  Although I do not know Haskell my understanding is that this
> is how it works as well.
> 
> For instance you could have:
> fun times x y = x * y;
> 
> You could then apply this function to either reals, ints, or one of each
> and then it would return the appropriate type.  The compiler will trace
> the execution through the function, deducing which are legal types from
> the operators and functions used within the function.  In this way you do
> not need to write a separate function for each combination of types your
> functions might want to operate on, even though ML is a statically typed
> language.
> 
> But because the checking is all done at compile-time you do not have much
> risk of runtime errors due to type problems.
> 
> 
> -- 
> To UNSUBSCRIBE, email to [EMAIL PROTECTED] 
> with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]
> 
> 

--David
David Teague, [EMAIL PROTECTED]
Debian GNU/Linux Because software support is free, timely,
 useful, technically accurate, and friendly.
 (I hope this is all of the above.)



Re: OT: Language War (Re: "C" Manual)

2002-01-01 Thread William T Wilson
On Tue, 1 Jan 2002, Richard Cobbe wrote:

> > | Casting you can't really get away from nor do you really need to.  In fact
> > | the more strongly typed the language is, the more casting you have to do.
> > 
> > This statement is incorrect.
> 
> Agreed.

I suppose I will agree as well, I was not meaning to include dynamically
typed languages in the original statement, I just didn't say that :}
Really it was not a very good statement to make, although in the original
context it wasn't so bad :}

> However, I think that the flexibility of a type system is more
> important than its `strength' for removing the need for casts.

I will go along with that as well.  In ML for instance (and other
languages as well) there is parametric polymorphism which give you a lot
of the flexibility of dynamic typing while still retaining much of the
error checking of static typing.  This is different from the
"polymorphism" found in C++ in which you can have virtual functions (which
still require the programmer to provide all the different implementations)
and inheritance (which only permits polymorphism within a very limited set
of types).  Although I do not know Haskell my understanding is that this
is how it works as well.

For instance you could have:
fun times x y = x * y;

You could then apply this function to either reals, ints, or one of each
and then it would return the appropriate type.  The compiler will trace
the execution through the function, deducing which are legal types from
the operators and functions used within the function.  In this way you do
not need to write a separate function for each combination of types your
functions might want to operate on, even though ML is a statically typed
language.

But because the checking is all done at compile-time you do not have much
risk of runtime errors due to type problems.



Re: OT: Language War (Re: "C" Manual)

2002-01-01 Thread Ben Collins
On Tue, Jan 01, 2002 at 10:12:09AM -0600, Richard Cobbe wrote:
> 
> > Secondly, you can make this mistake with any language that allows
> > references (perl, python, and java all allow it). Just replace free()
> > with some other assignment that changes what a is, and ultimately you
> > change b, which referenced it, unintentionally.
> 
> True.  That, however, is not a type error of the sort that I'm
> describing.  And, in any case, the behavior of the program in that
> situation is well-defined by the language specification.  This is *not*
> the case with C or C++.

Of course it is defined. It says that after you free() an allocation,
that the memory the pointer references is gone and using the pointer
afterwards is undefined.

Saying it is undefined is as good as defining the behavior. Assuming
anything after that point is broken.

-- 
 .--===-=-==-=---==-=-.
/   Ben Collins--Debian GNU/Linux  \
`  [EMAIL PROTECTED]  --  [EMAIL PROTECTED]  --  [EMAIL PROTECTED]  '
 `---=--===-=-=-=-===-==---=--=---'



Re: OT: Language War (Re: "C" Manual)

2002-01-01 Thread dman
On Tue, Jan 01, 2002 at 10:34:25AM -0600, Richard Cobbe wrote:
| Lo, on Tuesday, January 1, dman did write:
| 
| > On Mon, Dec 31, 2001 at 09:27:36PM -0500, William T Wilson wrote:
| >  
| > | Casting you can't really get away from nor do you really need to.  In fact
| > | the more strongly typed the language is, the more casting you have to do.
| > 
| > This statement is incorrect.
| 
| Agreed.
| 
| > The strength and staticness of typing are two independent properties.
| 
| Also agreed.

Cool, I'm glad you know this stuff too!

| However, I think that the flexibility of a type system is more important
| than its `strength' for removing the need for casts.

This sounds like a reasonable statement.

| When do people use typecasts in C/C++?  In my experience, they tend to
| happen in the following situations:
  
|   2) downcasts in a class hierarchy, as in Java.  (Note that `upcasts'
|  aren't really casts: if B is a subclass of A, then an instance of B
|  *is* an instance of A, no cast needed.)

This is only needed with unintelligent compiler.  *You* know you have
a B at runtime, but the compiler doesn't so it whines and complains.
Thus you must "cast" the pointer/reference to appease the compiler.
The cast in java doesn't do anything else (aside from a runtime
verification as well)[1].

|   3) Accessing external data in a callback function.  Callbacks in C and
|  C++ often take a void* parameter that points to data supplied by
|  the programmer when he registers the callback; to access this data,
|  it is necessary to cast it back to the original type.

I don't know about C++ frameworks that do this, but C's type system
certainly requires this.  In Java the callback is a class instance
anyways (since functions are not objects, nor can you take the address
of one).

| How do more flexible type systems handle these?
 
|   2) As several people have pointed out, too many downcasts indicate a
|  design flaw.

I agree here.

|  They are, however, useful in some situations, so (I
|  believe) many advanced languages with a static type system support
|  these.  However, as in Java, there's a run-time check that goes
|  with it.  C++'s dynamic_cast gets this right.

Take CORBA for example.  With python, you just have an object with the
given methods.  No problem, no difficulty.  With java you have to use
a special "narrow" method to create an instance of a class that
implements the interface, but does so in terms of corba calls.  With
the inflexible type system java uses, the downcast-wannabe is
necessary (ugh!).

|   3) There are a variety of strategies here.  My personal favorite is
|  to use first-class closures to implement callbacks; the external
|  data is no longer supplied as a parameter but is simply available
|  to the callback function due to normal scoping rules.

This sounds good to me :-).

|  If you're using a language without closures, like C++ or Java,
|  you can hack it up:

In java you _have_ to hack it up like this (for example,
java.lang.Runnable).

| template
| void register_callback(void (* cb)(T), T data);

That's not so bad, if you can stand the bloat this creates (C++
templates are expanded at compile time, thus you get one copy of this
function for each type it needs to work with).

| > I've heard that haskell has an even better type system, but I haven't
| > had time to learn it yet.
| 
| Most of my experience with advanced programming languages has been in
| Scheme, which (despite what many people believe) *is* strongly-typed and
| type-safe, but it checks all types at runtime rather than compile time.
| As a result, I'm not really up on languages with compile-time type
| verifications systems, though I've been meaning to investigate them for
| a while now.  At any rate: I've heard that ML's type system is easier to
| learn than Haskell's; you may want to start there first.

Ok, I might do that.  I've heard a lot about various languages on
comp.lang.python, and one particular guru (he's a C++ guru also)
frequently mentions Haskell's typeclasses in flamewars regarding type
systems.

-D

[1] with "primitive" types, I think java may do some conversion
(certainly with float->int it must), but I'm not totally sure (I
think with int->byte it doesn't, just truncates)

-- 

The Lord detests all the proud of heart.
Be sure of this: They will not go unpunished.
Proverbs 16:7



Re: OT: Language War (Re: "C" Manual)

2002-01-01 Thread Richard Cobbe
Lo, on Tuesday, January 1, dman did write:

> On Mon, Dec 31, 2001 at 09:27:36PM -0500, William T Wilson wrote:
>  
> | Casting you can't really get away from nor do you really need to.  In fact
> | the more strongly typed the language is, the more casting you have to do.
> 
> This statement is incorrect.

Agreed.

> The strength and staticness of typing are two independent properties.

Also agreed.

However, I think that the flexibility of a type system is more important
than its `strength' for removing the need for casts.

When do people use typecasts in C/C++?  In my experience, they tend to
happen in the following situations:

  1) conversions between data types (char and int, int and float, etc.)
 
  2) downcasts in a class hierarchy, as in Java.  (Note that `upcasts'
 aren't really casts: if B is a subclass of A, then an instance of B
 *is* an instance of A, no cast needed.)

  3) Accessing external data in a callback function.  Callbacks in C and
 C++ often take a void* parameter that points to data supplied by
 the programmer when he registers the callback; to access this data,
 it is necessary to cast it back to the original type.

How do more flexible type systems handle these?

  1) There are conversion functions.  Scheme does this with, e.g.,
 char->integer and integer->char, or exact->inexact and
 inexact->exact.  (The latter two convert between integers and
 floating point numbers.)  In many cases, this is what C's casts and
 C++'s static_cast really do; they just use a typecast notation.
 Many programmers tend to follow this trend when writing their own
 conversions, although I usually don't---implicit conversions worry
 me.

  2) As several people have pointed out, too many downcasts indicate a
 design flaw.  They are, however, useful in some situations, so (I
 believe) many advanced languages with a static type system support
 these.  However, as in Java, there's a run-time check that goes
 with it.  C++'s dynamic_cast gets this right.

  3) There are a variety of strategies here.  My personal favorite is
 to use first-class closures to implement callbacks; the external
 data is no longer supplied as a parameter but is simply available
 to the callback function due to normal scoping rules.  If you're
 using a language without closures, like C++ or Java, you can hack
 it up:

 class Closure
 {
 public:
 virtual void invoke(void) = 0;
 };

 Subclass this, implement invoke(), and supply a reference to the
 subclass instance as your callback function.  The data normally
 recognized by the void* is now private data members in the callback
 instance; no cast necessary.

 Alternatively, supply the callback system with enough smarts to
 handle types.  Instead of

void register_callback(void (* cb)(void *), void *data);

write something like

template
void register_callback(void (* cb)(T), T data);

although most advanced languages typically use a more concise
mechanism for this sort of polymorphism.

With the exception of downcasts, casting is generally only necessary if
your type system isn't very expressive.

> I've heard that haskell has an even better type system, but I haven't
> had time to learn it yet.

Most of my experience with advanced programming languages has been in
Scheme, which (despite what many people believe) *is* strongly-typed and
type-safe, but it checks all types at runtime rather than compile time.
As a result, I'm not really up on languages with compile-time type
verifications systems, though I've been meaning to investigate them for
a while now.  At any rate: I've heard that ML's type system is easier to
learn than Haskell's; you may want to start there first.

Richard



Re: OT: Language War (Re: "C" Manual)

2002-01-01 Thread Richard Cobbe
Lo, on Tuesday, January 1, Ben Collins did write:

> On Mon, Dec 31, 2001 at 09:15:26PM -0600, Richard Cobbe wrote:
> 
> > Consider the following:
> > 
> > char *a, *b;
> > 
> > a = strdup("This is a sample string");
> > b = a;
> > 
> > free(a);
> > 
> > /* Much code follows here, none of which modifies b. */
> > 
> > printf("%s\n", b);
> 
> Uh, for one, this wont segfault.

Perhaps, perhaps not.  That's the thing about C---the behavior in this
case is completely undefined.  Since printf is looking for a byte with a
value of zero, if it doesn't find such a byte before it walks off the
end of the process's allocated memory, it will segfault.

> Secondly, you can make this mistake with any language that allows
> references (perl, python, and java all allow it). Just replace free()
> with some other assignment that changes what a is, and ultimately you
> change b, which referenced it, unintentionally.

True.  That, however, is not a type error of the sort that I'm
describing.  And, in any case, the behavior of the program in that
situation is well-defined by the language specification.  This is *not*
the case with C or C++.

Richard



Re: OT: Language War (Re: "C" Manual)

2002-01-01 Thread Ben Collins
On Mon, Dec 31, 2001 at 03:46:38PM -0800, Eric G. Miller wrote:
> 
> Well, I dare you to remove 'ld' or 'libc.so' and see how many programs
> run ;-)  I think it's fair to characterize required language libraries
> as part of the "run time" system.  Whether or not a program is statically
> compiled is unimportant, as the language library still performs actions
> at runtime that "your" program depends on, and which "your" program
> could not function without.  Among those things, might be checking
> array accesses and raising exceptions for range errors...

I assume you mean ld.so.

The fact is that the C library is not needed in order to use C (else
libc.so would require itself in a neverending loop). You can easily
write C programs that use nothing from libc.so/libc.a. You can't write
java, perl and python that don't need their runtime.

The Linux kernel is an excellent example of a C program that is
self-contained.

Think of libraries as conveniences, not requirements.

I would also point out that java, python, php and perl runtime are
written in _C_. It's easy to characterize an interpreted language by
noting that it's runtime executable is written in a language other than
itself.

-- 
 .--===-=-==-=---==-=-.
/   Ben Collins--Debian GNU/Linux  \
`  [EMAIL PROTECTED]  --  [EMAIL PROTECTED]  --  [EMAIL PROTECTED]  '
 `---=--===-=-=-=-===-==---=--=---'



Re: OT: Language War (Re: "C" Manual)

2002-01-01 Thread Ben Collins
On Mon, Dec 31, 2001 at 09:15:26PM -0600, Richard Cobbe wrote:
> 
> > most of the segfaults are because of the resource allocation mistakes,
> > not because of mistaken types... at last that's my impression.
> 
> Resource allocation mistakes (at least, the kind that typically lead to
> seg faults) *are* type errors, from a certain point of view.
> 
> Consider the following:
> 
> char *a, *b;
> 
> a = strdup("This is a sample string");
> b = a;
> 
> free(a);
> 
> /* Much code follows here, none of which modifies b. */
> 
> printf("%s\n", b);

Uh, for one, this wont segfault.

Secondly, you can make this mistake with any language that allows
references (perl, python, and java all allow it). Just replace free()
with some other assignment that changes what a is, and ultimately you
change b, which referenced it, unintentionally.

-- 
 .--===-=-==-=---==-=-.
/   Ben Collins--Debian GNU/Linux  \
`  [EMAIL PROTECTED]  --  [EMAIL PROTECTED]  --  [EMAIL PROTECTED]  '
 `---=--===-=-=-=-===-==---=--=---'



Re: OT: Language War (Re: "C" Manual)

2001-12-31 Thread dman
On Mon, Dec 31, 2001 at 09:27:36PM -0500, William T Wilson wrote:
 
| Casting you can't really get away from nor do you really need to.  In fact
| the more strongly typed the language is, the more casting you have to do.

This statement is incorrect.  The strength and staticness of typing
are two independent properties.  There are strongly statically typed
languages, weakly statically typed languages, strongly dynamically
typed languages, and weakly dynamically typed languages.  Casting only
exists in statically typed langauges (such as C, C++ and Java) and does
not exist in dynamically typed languages (such as Python and Haskell).
However C is farily weakly typed, and C++ is only moderately strongly
typed.  Python and haskell, OTOH, are strongly typed.  You can never
consider an object (collection of bits) as something that it is not,
which is what casting in C and C++ allows you to do.  The reason I
like python so much is that the dynamic typing creates a lot of
flexibility that C, C++ and Java lack, but it doesn't create the type
errors that those languages are prone to.  I've heard that haskell has
an even better type system, but I haven't had time to learn it yet.

-D

-- 

Stay away from a foolish man,
for you will not find knowledge on his lips.
Proverbs 14:7



Re: OT: Language War (Re: "C" Manual)

2001-12-31 Thread Richard Cobbe
Lo, on Monday, December 31, Erik Steffl did write:

> "Eric G. Miller" wrote:
> > 
> > On Mon, 31 Dec 2001 13:46:15 -0800, Erik Steffl <[EMAIL PROTECTED]> wrote:
> > 
> > > Richard Cobbe wrote:
> > > >
> > > > Lo, on Sunday, December 30, Dimitri Maziuk did write:
> > > >
> > > > > * William T Wilson ([EMAIL PROTECTED]) spake thusly:
> > > > > ...
> > > > > > So... why *should* the programmer concern himself with
> > > > > > individual bytes of memory? (Assuming he is writing an
> > > > > > ordinary application and not a hardware driver or something
> > > > > > similar).
> > > > >
> > > > > Because if he does not, his application will segfault and dump
> > > > > core.
> > > >
> > > > No.  This level of concern is necessary only for non-type-safe
> > > > languages.  It is provably impossible for a program written in a
> > > > type-safe language to segfault (assuming that the language's
> > > > run-time system is implemented correctly, of course).
> > >
> > >???
> > >
> > > it's the resource allocation that's important, not types. garbage
> > > collectors are generally more robust as far as segfaulting (and
> > > similar errors) go (of course, just because the program doesn't
> > > segfault it doen't mean it's working correctly). the other
> > > important factor is how much runtime check language does
> > > (e.g. checking for array boundaries etc.)
> > 
> > But it's the type safety of the language that prevents the abuse of
> > memory, not how it was allocated.  Strong typing eliminates a huge
> > number of error cases.  C and C++ both subvert the ability of the
> > compiler to do static type checking via casts and void pointers.
> > Strong static type checking also has the possible advantage that the
> > compiler can better optimize the generated code.
> 
> consider perl which doesn't have strong types but it's quite
> impossible to make it segfault and C++ on the other side which is
> fairly dangerous even without casting (I would even go as far as
> saying that casting makes no difference (statistally), but I'd have to
> think about it).

Perl does have strong types, but they don't really correspond to the
types that most people are used to thinking of.  Perl's types are

* scalars (no real distinction between strings, numbers, and the
  undefined value)
* lists
* hashes
* filehandles

(I haven't really used Perl since Perl 4, so this list may not be
complete.)

> most of the segfaults are because of the resource allocation mistakes,
> not because of mistaken types... at last that's my impression.

Resource allocation mistakes (at least, the kind that typically lead to
seg faults) *are* type errors, from a certain point of view.

Consider the following:

char *a, *b;

a = strdup("This is a sample string");
b = a;

free(a);

/* Much code follows here, none of which modifies b. */

printf("%s\n", b);

This may or may not segfault, but it's obviously not correct.  The
problem is, in fact, a type error in the reference to b in the printf()
call.  The compiler and library think that b is a pointer to a
null-terminated character string, but this is in fact not the case.  In
a type-safe language, you would not be allowed to bring about this state
of affairs.

> also note that in java you have to cast (when getting items from
> containers) but it doesn't make java programs more likely to segfault.

That's because Java's typecasts are safe (i.e., checked at run-time):
they're equivalent to C++'s dynamic_cast, not static_cast.  (Casting a
float to an int, of course, is equivalent to C++'s static_cast, but
errors with those sorts of casts are not likely to cause memory
problems.)

> > >   and as far as runtime system goes - only interpreted languages have
> > > runtime systems.
> > 
> > Well, I dare you to remove 'ld' or 'libc.so' and see how many programs
> > run ;-)  I think it's fair to characterize required language libraries
> > as part of the "run time" system.  Whether or not a program is statically
> > compiled is unimportant, as the language library still performs actions
> > at runtime that "your" program depends on, and which "your" program
> > could not function without.  Among those things, might be checking
> > array accesses and raising exceptions for range errors...
> 
> IMO the important distinction is whether the program runs itself
> (compiled programs) or whether it is run by other program, which
> controls it and takes care of various runtime checks etc.

Performing run-time checks, as with array indexing, does not necessarily
imply the existence of an interpreter.  If a compiler sees the
expression a[i], it can either assume that i's value is a valid index
for the array a (as C and C++ do), or it can insert the appropriate
checks directly into the executable code.  I still claim this is part of
the language's run-time system, regardless of how it's interpreted.

> you do not necessarily need ld and standard libraries for c or c++
> program, however

Re: OT: Language War (Re: "C" Manual)

2001-12-31 Thread William T Wilson
On Mon, 31 Dec 2001, Erik Steffl wrote:

>   consider perl which doesn't have strong types but it's quite
> impossible to make it segfault and C++ on the other side which is

That is true but it doesn't mean that type safety won't prevent it
also.  Consider a hypothetical language that doesn't have any dynamic
resource allocation at all and has a very weak type system.  Actually a
shell scripting language is not very far from this.  It can never segfault
although it is still possible to have the same sort of bugs which cause
segfaults.

> fairly dangerous even without casting (I would even go as far as
> saying that casting makes no difference (statistally), but I'd have to
> think about it).

The presence of casting doesn't have too much of an impact on the
reliability of a particular program (if anything it improves it because it
means the programmer thought about what his data really meant) but a
language that doesn't keep track of the type of its data on the
programmer's behalf cannot detect many errors at compile-time.

It can make sure that the programmer doesn't try to access a field that
isn't present in the type of data that the pointer is supposed to
represent, but it can't make sure that the pointer actually points to that
sort of data.

The ability to check that the pointer points to the right type of data
catches both a huge number of nuisance bugs *and* detects many types of
segfaulting bugs even at compile time (and provides useful error
descriptions even if it slips through to runtime).

Programmers that haven't used a really strongly typed language may not
even even realize that the compiler is able to catch these sorts of bugs.

>   most of the segfaults are because of the resource allocation
> mistakes, not because of mistaken types... at last that's my
> impression.

In a lot of ways they are the same thing.  Suppose you have a pointer to
an integer, and you change it so it points to a dynamically allocated
array of pointers to integers (i.e. a 2-dimensional array) - which is
perfectly legal in C - and then you free() the pointer.  Is this a
resource allocation mistake or a type mistake?  It's really a resource
allocation mistake, but it's also a type mistake, and it's something that
a compiler in a strongly typed language would catch.

>   note that in c++ there's basically no need for casting and using
> void pointers (in general, there are special cases). That's of course,

Casting you can't really get away from nor do you really need to.  In fact
the more strongly typed the language is, the more casting you have to do.

(void) pointers on the other hand are generally not your friend :}



Re: OT: Language War (Re: "C" Manual)

2001-12-31 Thread Erik Steffl
"Eric G. Miller" wrote:
> 
> On Mon, 31 Dec 2001 13:46:15 -0800, Erik Steffl <[EMAIL PROTECTED]> wrote:
> 
> > Richard Cobbe wrote:
> > >
> > > Lo, on Sunday, December 30, Dimitri Maziuk did write:
> > >
> > > > * William T Wilson ([EMAIL PROTECTED]) spake thusly:
> > > > ...
> > > > > So... why *should* the programmer concern himself with individual
> > > > > bytes of memory? (Assuming he is writing an ordinary application and
> > > > > not a hardware driver or something similar).
> > > >
> > > > Because if he does not, his application will segfault and dump core.
> > >
> > > No.  This level of concern is necessary only for non-type-safe
> > > languages.  It is provably impossible for a program written in a
> > > type-safe language to segfault (assuming that the language's run-time
> > > system is implemented correctly, of course).
> >
> >???
> >
> >   it's the resource allocation that's important, not types. garbage
> > collectors are generally more robust as far as segfaulting (and similar
> > errors) go (of course, just because the program doesn't segfault it
> > doen't mean it's working correctly). the other important factor is how
> > much runtime check language does (e.g. checking for array boundaries
> > etc.)
> 
> But it's the type safety of the language that prevents the abuse of
> memory, not how it was allocated.  Strong typing eliminates a huge
> number of error cases.  C and C++ both subvert the ability of the
> compiler to do static type checking via casts and void pointers.  Strong
> static type checking also has the possible advantage that the compiler
> can better optimize the generated code.

  consider perl which doesn't have strong types but it's quite
impossible to make it segfault and C++ on the other side which is fairly
dangerous even without casting (I would even go as far as saying that
casting makes no difference (statistally), but I'd have to think about
it).

  most of the segfaults are because of the resource allocation mistakes,
not because of mistaken types... at last that's my impression.

  note that in c++ there's basically no need for casting and using void
pointers (in general, there are special cases). That's of course, if you
are willing to use templates (or, alternatively, multiple inheritance,
in some cases).

  also note that in java you have to cast (when getting items from
containers) but it doesn't make java programs more likely to segfault.

> >   and as far as runtime system goes - only interpreted languages have
> > runtime systems.
> 
> Well, I dare you to remove 'ld' or 'libc.so' and see how many programs
> run ;-)  I think it's fair to characterize required language libraries
> as part of the "run time" system.  Whether or not a program is statically
> compiled is unimportant, as the language library still performs actions
> at runtime that "your" program depends on, and which "your" program
> could not function without.  Among those things, might be checking
> array accesses and raising exceptions for range errors...

  IMO the important distinction is whether the program runs itself
(compiled programs) or whether it is run by other program, which
controls it and takes care of various runtime checks etc.

  you do not necessarily need ld and standard libraries for c or c++
program, however you need vm for java program.

  or, in other words - runtime for compiled program is HW, runtime for
interpreted program is SW (HW usually provides generic, basic &
low-level functionality, SW usually does provide higher level
functionality, specific for given language).

  so IMO the 'runtime' for compiled languages (c, c++ etc.) is a lot
different from what 'runtime' means when talking about interpreted
languages (java, perl, VB)

erik



Re: OT: Language War (Re: "C" Manual)

2001-12-31 Thread Eric G . Miller
On Mon, 31 Dec 2001 13:46:15 -0800, Erik Steffl <[EMAIL PROTECTED]> wrote:

> Richard Cobbe wrote:
> > 
> > Lo, on Sunday, December 30, Dimitri Maziuk did write:
> > 
> > > * William T Wilson ([EMAIL PROTECTED]) spake thusly:
> > > ...
> > > > So... why *should* the programmer concern himself with individual
> > > > bytes of memory? (Assuming he is writing an ordinary application and
> > > > not a hardware driver or something similar).
> > >
> > > Because if he does not, his application will segfault and dump core.
> > 
> > No.  This level of concern is necessary only for non-type-safe
> > languages.  It is provably impossible for a program written in a
> > type-safe language to segfault (assuming that the language's run-time
> > system is implemented correctly, of course).
> 
>???
> 
>   it's the resource allocation that's important, not types. garbage
> collectors are generally more robust as far as segfaulting (and similar
> errors) go (of course, just because the program doesn't segfault it
> doen't mean it's working correctly). the other important factor is how
> much runtime check language does (e.g. checking for array boundaries
> etc.)

But it's the type safety of the language that prevents the abuse of
memory, not how it was allocated.  Strong typing eliminates a huge
number of error cases.  C and C++ both subvert the ability of the
compiler to do static type checking via casts and void pointers.  Strong
static type checking also has the possible advantage that the compiler
can better optimize the generated code.

>   and as far as runtime system goes - only interpreted languages have
> runtime systems.

Well, I dare you to remove 'ld' or 'libc.so' and see how many programs
run ;-)  I think it's fair to characterize required language libraries
as part of the "run time" system.  Whether or not a program is statically
compiled is unimportant, as the language library still performs actions
at runtime that "your" program depends on, and which "your" program
could not function without.  Among those things, might be checking
array accesses and raising exceptions for range errors...

-- 
Eric G. Miller 



Re: OT: Language War (Re: "C" Manual)

2001-12-31 Thread Erik Steffl
Richard Cobbe wrote:
> 
> Lo, on Sunday, December 30, Dimitri Maziuk did write:
> 
> > * William T Wilson ([EMAIL PROTECTED]) spake thusly:
> > ...
> > > So... why *should* the programmer concern himself with individual
> > > bytes of memory? (Assuming he is writing an ordinary application and
> > > not a hardware driver or something similar).
> >
> > Because if he does not, his application will segfault and dump core.
> 
> No.  This level of concern is necessary only for non-type-safe
> languages.  It is provably impossible for a program written in a
> type-safe language to segfault (assuming that the language's run-time
> system is implemented correctly, of course).

   ???

  it's the resource allocation that's important, not types. garbage
collectors are generally more robust as far as segfaulting (and similar
errors) go (of course, just because the program doesn't segfault it
doen't mean it's working correctly). the other important factor is how
much runtime check language does (e.g. checking for array boundaries
etc.)

  and as far as runtime system goes - only interpreted languages have
runtime systems.

erik



Re: OT: Language War (Re: "C" Manual)

2001-12-31 Thread Richard Cobbe
Lo, on Sunday, December 30, Dimitri Maziuk did write:

> * William T Wilson ([EMAIL PROTECTED]) spake thusly:
> ...
> > So... why *should* the programmer concern himself with individual
> > bytes of memory? (Assuming he is writing an ordinary application and
> > not a hardware driver or something similar).
> 
> Because if he does not, his application will segfault and dump core.

No.  This level of concern is necessary only for non-type-safe
languages.  It is provably impossible for a program written in a
type-safe language to segfault (assuming that the language's run-time
system is implemented correctly, of course).

Richard



Re: OT: Language War (Re: "C" Manual)

2001-12-30 Thread David Teague

Hi 

Joyner's article is very old. Has he updated it recently?

I didn't care much for Joyner's article either, but I learned a
great deal about C++ from reading it.

If you want or need to deal with the hardware, then you should use a
language that permits this access. If not, then by what ever you
hold holy, choose a language that insulates you from the hardware. 

You choose your advice by choosing your advisor. If you don't
believe me, consider asking a Priest about birth control.

Eiffel, Java, Ada fill this bill of a language that insulates from
the hardware.

--David



Listen folks, you choose your advice by choosing your advior. On
Sat, 29 Dec 2001, Jeffrey W. Baker wrote:

> 
> 
> On Sat, 29 Dec 2001, Eric G. Miller wrote:
> 
> > For a good explanation of how C++ took all the problematic issues of C and
> > added new sources of errors, see http://www.elj.com/cppcv3/.
> 
> Hah!  More like this:
> 
> "For a vivid example of how much free time ivory tower academics have to
> weep and moan about languages other than their favorite, see
> http://www.elj.com/cppcv3/";
> 
> I mean, really.  I've read all three editions of this guy whining about
> C++ (and C) and I don't think I can take it any longer.  "Be like me, use
> a language with imperceptible market penetration."  I really think Mr.
> Joyner is my polar opposite.  When I think of a computer, I think of an
> electronic device which will do such-and-such thing if you place value
> 0x37 at memory offset 0.  When Ian Joyner looks at a computer, he wants to
> represent his model of the universe inside it.  The computer and the human
> are fundametally different things.  You'll expend an aweful lot of energy
> trying to represent human concepts in a computer.  By contrast, it is very
> easy for a human to learn computer concepts.
> 
> If you ask an Eiffel programmer how to get the value of a byte at a given
> offset in the computer's memory, they'll start with an explanation about
> why the programmer shouldn't concern himself with computer memory; memory
> is in the "how" domain.  From there, they will launch a long lecture that
> probably won't answer the question but will result in something absurd
> like class ByteObserver (and its companion, class ByteObserverManager).
> A C programmer will just say *offset.
> 
> Anyway, back to "A Critique of C++"...
> 
> Mr. Joyner's treatise shouldn't be considered anything other than a
> finely-ground axe.  Many of his specific criticisms start out "It is well
> known..." or "It hash been shown..." without reference to the place where
> it has been shown or the people to whom it is well known.  In one place,
> he complains that C++ is not suited to concurrent processing (without
> reference to the tremendous amount of existing concurrent C++ software --
> Mozilla is a modern example), but fails to mention that, at the time of
> his writing, Eiffel lacked support for concurrency altogether!
> 
> Someday, if I suddenly become a bored academic, I'll write a complete
> critique of Mr. Joyner's critique.  At the current time, I am too busy
> writing actual software.
> 
> -jwb
> 
> 
> -- 
> To UNSUBSCRIBE, email to [EMAIL PROTECTED] 
> with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]
> 
> 

--David
David Teague, [EMAIL PROTECTED]
Debian GNU/Linux Because software support is free, timely,
 useful, technically accurate, and friendly.
 (I hope this is all of the above.)



Re: OT: Language War (Re: "C" Manual)

2001-12-30 Thread Craig Dickson
Dimitri Maziuk wrote:
> * William T Wilson ([EMAIL PROTECTED]) spake thusly:
> ...
> > So... why *should* the programmer concern himself with individual bytes of
> > memory? (Assuming he is writing an ordinary application and not a hardware
> > driver or something similar).
> 
> Because if he does not, his application will segfault and dump core.

Not if he's writing in a reasonable language for high-level applications
that takes care of all that stuff.

Craig



Re: OT: Language War (Re: "C" Manual)

2001-12-30 Thread Dimitri Maziuk
* William T Wilson ([EMAIL PROTECTED]) spake thusly:
...
> So... why *should* the programmer concern himself with individual bytes of
> memory? (Assuming he is writing an ordinary application and not a hardware
> driver or something similar).

Because if he does not, his application will segfault and dump core.

Dima
-- 
Well, lusers are technically human.-- Red Drag Diva



Re: OT: Language War (Re: "C" Manual)

2001-12-29 Thread Craig Dickson
William T Wilson wrote:

> But then no one derives any real
> benefit from having 0x37 placed at offset 0.

That depends what memory address 0 is used for in the target platform.
It may be a significant thing to the CPU, or to some memory-mapped
peripheral, and therefore to the kernel. This is one reason that C is a
useful language for hardware drivers and similarly low-level things. The
value of address 0 isn't something a user-level app should have to worry
about, though.

> Representing human concepts in a computer is the central purpose of
> programming.

Yes. On the one hand, low-level tools are essential for creating
frameworks in which higher-level tools can operate. But the higher-level
tools are the source of the computer's value. Nobody except OS
researchers buys a computer just to run device drivers and memory
managers on it; the real value of a computer to most people is the
ability to use it for tasks which essentially have nothing to do with
the computer, but which the computer makes easier, or can do faster, or
less expensively.

Craig



Re: OT: Language War (Re: "C" Manual)

2001-12-29 Thread Eric G . Miller
On Sat, 29 Dec 2001 16:39:48 -0800 (PST), "Jeffrey W. Baker" <[EMAIL 
PROTECTED]> wrote:

> 
> 
> On Sat, 29 Dec 2001, Eric G. Miller wrote:
> 
> > For a good explanation of how C++ took all the problematic issues of C and
> > added new sources of errors, see http://www.elj.com/cppcv3/.
> 
> Hah!  More like this:
> 
> "For a vivid example of how much free time ivory tower academics have to
> weep and moan about languages other than their favorite, see
> http://www.elj.com/cppcv3/";

Well, I won't disagree there a bit of "ivory tower" in the essay.  And I'll
also agree that the pragmatic solution often overrides the better solution.
I'm also not sold on the fully OOP paradigm of languages like Java or
Eiffel.  But many/most of the criticisms are valid in light of sources of
confusion and the error prone nature of "C" and "C++".  Some of the
criticisms are plainly irrelevant unless you accept that OOP is the one
true way ("when you have classes, you don't need structs").

> If you ask an Eiffel programmer how to get the value of a byte at a given
> offset in the computer's memory, they'll start with an explanation about
> why the programmer shouldn't concern himself with computer memory; memory
> is in the "how" domain.  From there, they will launch a long lecture that
> probably won't answer the question but will result in something absurd
> like class ByteObserver (and its companion, class ByteObserverManager).
> A C programmer will just say *offset.

Yea, sometimes it's important to know.  Often it isn't.  More often what's
really wanted is an index into an array or other data structure and it
little matters whether that offset is a real memory location or it just
maps to one.  Obviously, it depends on the problem domain...

> Anyway, back to "A Critique of C++"...
> 
> Mr. Joyner's treatise shouldn't be considered anything other than a
> finely-ground axe.  Many of his specific criticisms start out "It is well
> known..." or "It hash been shown..." without reference to the place where
> it has been shown or the people to whom it is well known.  In one place,
> he complains that C++ is not suited to concurrent processing (without
> reference to the tremendous amount of existing concurrent C++ software --
> Mozilla is a modern example), but fails to mention that, at the time of
> his writing, Eiffel lacked support for concurrency altogether!

Well, you're not claiming concurrency is a part of C++ are you?  It is,
however, built into a language like Ada95.

Anyway, I think it's important to be cognizant of the shortcomings of
any language/platform and to actively look for alternatives.  Obviously,
it is not always feasible to change programming language for a project.

-- 
Eric G. Miller 



Re: OT: Language War (Re: "C" Manual)

2001-12-29 Thread William T Wilson
On Sat, 29 Dec 2001, Jeffrey W. Baker wrote:

> about C++ (and C) and I don't think I can take it any longer.  "Be
> like me, use a language with imperceptible market penetration."  I

Why does market penetration matter?  It's like saying Windows is superior
because everyone uses it; but if you believed that you probably wouldn't
be here.

> really think Mr. Joyner is my polar opposite.  When I think of a
> computer, I think of an electronic device which will do such-and-such
> thing if you place value 0x37 at memory offset 0.  When Ian Joyner

That's because that's what it is.  But then no one derives any real
benefit from having 0x37 placed at offset 0.

> looks at a computer, he wants to represent his model of the universe
> inside it.  The computer and the human are fundametally different

Which is a much more valuable task!  No wonder he wants to do that.

> things.  You'll expend an aweful lot of energy trying to represent
> human concepts in a computer.  By contrast, it is very easy for a
> human to learn computer concepts.

Representing human concepts in a computer is the central purpose of
programming.

> If you ask an Eiffel programmer how to get the value of a byte at a
> given offset in the computer's memory, they'll start with an
> explanation about why the programmer shouldn't concern himself with
> computer memory; memory is in the "how" domain.  From there, they will

So... why *should* the programmer concern himself with individual bytes of
memory? (Assuming he is writing an ordinary application and not a hardware
driver or something similar).



Re: OT: Language War (Re: "C" Manual)

2001-12-29 Thread Alec
On Saturday 29 December 2001 04:55 pm, Craig Dickson wrote:

> That language shootout didn't really mean much. 

Not the shootout specifically, but simple benchmarks can mean something. 
Depends on who you ask. If you are doing numerical analysis, like me, or 
artificial neural networks, or genetic algorithms, you may be unwilling to 
take a, say, 800% penalty in array access time or list sorting, etc. 
regardless of what people tell you about their super-awesome ueber-language. 
If you are making GUIs, then yeah, use whatever, as long as I don't have to 
wait 10 seconds for the drop-down menu to appear. 9 seconds and less will not 
try my patience :)

Regards,

Alec
P.S. I apologize for being OT. This is my last post in this thread.



Re: OT: Language War (Re: "C" Manual)

2001-12-29 Thread Jeffrey W. Baker


On Sat, 29 Dec 2001, Eric G. Miller wrote:

> For a good explanation of how C++ took all the problematic issues of C and
> added new sources of errors, see http://www.elj.com/cppcv3/.

Hah!  More like this:

"For a vivid example of how much free time ivory tower academics have to
weep and moan about languages other than their favorite, see
http://www.elj.com/cppcv3/";

I mean, really.  I've read all three editions of this guy whining about
C++ (and C) and I don't think I can take it any longer.  "Be like me, use
a language with imperceptible market penetration."  I really think Mr.
Joyner is my polar opposite.  When I think of a computer, I think of an
electronic device which will do such-and-such thing if you place value
0x37 at memory offset 0.  When Ian Joyner looks at a computer, he wants to
represent his model of the universe inside it.  The computer and the human
are fundametally different things.  You'll expend an aweful lot of energy
trying to represent human concepts in a computer.  By contrast, it is very
easy for a human to learn computer concepts.

If you ask an Eiffel programmer how to get the value of a byte at a given
offset in the computer's memory, they'll start with an explanation about
why the programmer shouldn't concern himself with computer memory; memory
is in the "how" domain.  From there, they will launch a long lecture that
probably won't answer the question but will result in something absurd
like class ByteObserver (and its companion, class ByteObserverManager).
A C programmer will just say *offset.

Anyway, back to "A Critique of C++"...

Mr. Joyner's treatise shouldn't be considered anything other than a
finely-ground axe.  Many of his specific criticisms start out "It is well
known..." or "It hash been shown..." without reference to the place where
it has been shown or the people to whom it is well known.  In one place,
he complains that C++ is not suited to concurrent processing (without
reference to the tremendous amount of existing concurrent C++ software --
Mozilla is a modern example), but fails to mention that, at the time of
his writing, Eiffel lacked support for concurrency altogether!

Someday, if I suddenly become a bored academic, I'll write a complete
critique of Mr. Joyner's critique.  At the current time, I am too busy
writing actual software.

-jwb



Re: OT: Language War (Re: "C" Manual)

2001-12-29 Thread Eric G . Miller
For a good explanation of how C++ took all the problematic issues of C and
added new sources of errors, see http://www.elj.com/cppcv3/.

-- 
Eric G. Miller 



Re: OT: Language War (Re: "C" Manual)

2001-12-29 Thread Craig Dickson
Alec wrote:

> > You say that as if C were merely an 'unreal' C++, which is just not
> > true. They are two different languages, though obviously C++ is a
> > derivative of C. 
> 
> With minor exceptions, a valid C program is also a valid C++ program
> (See appendix B, chapter B.2.2 of "The C++ Programming Language" 
> for the list of incompatibilities)

Sort of. The new C99 standard shows that C is evolving away from being a
subset of C++ (which it never quite was, anyway -- even in the early
years of C++, it defined new keywords which were not reserved in C, so
there was always at least a minimal degree of incompatibility). Of
course, almost nobody supports C99, at least not yet.

> > Anyone interested in C++ should learn both, in order to
> > understand why C++ is the way it is. 
> 
> Opinions vary :)

Well, if you consider C++ worth learning at all.

>From a historical perspective, it's undeniable that C++ is what it is
because of its C ancestry, particularly the desire for maximal
backward-compatibility with C. This had major effects on the nature of
C++. Nobody in his right mind would design something like C++ if he just
wanted to make an efficient object-oriented language.

> I'm actually intersted in O'Caml. I'd like to see a few real C++ vs O'Caml 
> benchmarks though before I start learning the language. Doug's Great 
> Languages Shootout is not updated any more. I sent him an improved C++ 
> version of one of the benchmarks that ran 5.5 times faster, but he didn't 
> include it.

That language shootout didn't really mean much. It's nice that you sent
him an improved C++ program, but the real problems are that little
benchmarks don't really have much relevance to large systems, and
low-level languages like C are best applied to different problems than
high-level languages like OCaml. C is best at naturally low-level things
like hardware drivers, memory managers, and other basic kernel
functionality. More abstract languages are better for most user-level
applications other than trivial ones.

Craig



OT: Language War (Re: "C" Manual)

2001-12-29 Thread Alec
On Saturday 29 December 2001 01:13 pm, Craig Dickson wrote:
> wsa wrote:
> > As others have said stear clear of OS specific topics...
> > Even if you want to start using OS specific stuff later on i think it's
> > best to start out with real C++.
>
> You say that as if C were merely an 'unreal' C++, which is just not
> true. They are two different languages, though obviously C++ is a
> derivative of C. 

With minor exceptions, a valid C program is also a valid C++ program
(See appendix B, chapter B.2.2 of "The C++ Programming Language" 
for the list of incompatibilities)

> Anyone interested in C++ should learn both, in order to
> understand why C++ is the way it is. 

Opinions vary :)

> And should also learn a real OO
> language like OCaml or Smalltalk to see why C++ is such an atrocity,

I'm actually intersted in O'Caml. I'd like to see a few real C++ vs O'Caml 
benchmarks though before I start learning the language. Doug's Great 
Languages Shootout is not updated any more. I sent him an improved C++ 
version of one of the benchmarks that ran 5.5 times faster, but he didn't 
include it.

If anyone who knows Haskell or O'Caml is intersted in collaborating on this 
type of simple benchmark (Similar to http://www.bagley.org/~doug/shootout/).
let me know!

We might even create a *deb for it!

Alec

> > In my opinion you should even avoid 'plain' C because you'll end up
> > learning things you can ditch in C++ cause there are more effecient and
> > new ways of doing things in ++.
> >
> >
> > And make very sure whatever book you get really really restricts to
> > C++... cause there's a shitload of them that sneak in non C++ stuff like
> > the dreaded conio
>
> True, one must always be on the lookout for books that don't really want
> to teach you C++ (or C), but rather C++ or C for MS Windows. Even books
> that aren't Windows-specific rarely seem to discuss how to write
> portable code, though, so it'll be sheer luck if you end up writing
> anything really complex that works on platforms other than the one you
> developed it on.
>
> Craig