[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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



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<j) segfault()
> |   else    return (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<j) segfault();
    return (double)i * (double)j;
  }

  now specify Type (that can be used in the first line to define
variable i, suitable for operator *).

  it is obviously impossible because the type of i must be specified as
property of variable i while acceptable values for function are property
of function. the type and set of valid input values are not the same
(again, remember the math analysis courses, I guess you took some)

  notice that your solution above specified the condition as part of the
function (a precondition), not as part of the variable type.

> |   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, NOT for C language) of
> | character array.
> 
> When writing code in a statically typed language you do write out the
> valid values (invariants) separately from the "types" because of the
> limitations in the language.  When you write code in, eg, python, you
> only consider the valid values since those are what make up a type.
> 
> I've just come up with a good description of what a 'type' is :
>     A "type" is the set of all valid values.

  no it's not.

  type is a propert of variable.

  set of valid values is a property of operation.

  in some (lot of) cases you can specify the type in a way that all its
values are valid values for some function (and vice versa) but it's not
ALWAYS possible.

...
> 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<length).  The problem is that today's
> 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)

  you can implement assignment/creators of type and enforce values of
the variable of the given type (class) in some OO languages (C++, to
certain extend in perl etc.). It brings new meaning to 'dynamic' types
since the set of valid values can change in time:-) However you do not
know in which function the variable is used and therefore cannot make
sure that the value will be a valid value for given function. again:
type is a property of variable. set of valid values is property of
operation being performed

> One reason that we use names like "string" when discussing C
> programs/libraries/functions is because as humans we fully understand
> what the "string" type entails -- a certain subset of all the possible
> character arrays.  When we write that in C we write "char*" (or
> char[]) because the C compiler doesn't understand any more than that.
> Have you read the book "Design Patterns" by the Gang of Four?  That
> book carefully describes many patterns, all named, so that as
> developers we can simply mention the name in a discussion and each
> will understand what is intended.  This is better than re-inventing
> each pattern every time we use it because we limit our expressiveness
> to that of C (or C++ or Java or Assembly, or $LANGUAGE).  You are
> correct to say that The C/C++/Java/whatever compiler doesn't
> understand the type "Singleton", but as developers we know what it is.
> There are ways to approximate it in each language, but the compiler
> does not (cannot) check the correctness of your program.  It can only
> approximate it by asserting that the bit patterns shoved around are of
> the size (and to a limited extent, the order) the that you said
> you wanted.

  yes, that's true. that doesn't change the fact that the errors in C
that are result of 'string' not being zero-ended are problem of invalid
value passed, not invalid type. the situation might exist because of
limitations of C type system but it's still a value error, not type
error. char * is type that is to be passed to strcpy, some values of
this type might cause segfault (or other funny stuff).

> I feel I should say that I can see you understand C (and perhaps other
> languages) quite well and you do realize that "char*" is an incomplete
> description of what a string is.  I believe that you understand what I
> am saying, but the word "type" is not defined well enough nor
> universally enough, which is what fuels this discussion.

  yes, char * is obviously incomplete description of what we think of as
a string. but 'string' only exists in our heads - it's not C type and
therefore it's not C type error when str* function fails badly - it was
given a variable of proper type. In some other language or in theory it
WOULD be different... not in C.

  BTW just found about language D in latest (february 2002) dr. dobb's,
see either dr. dobb's or http://www.digitalmars.com/d (if you haven't
seen already). it's quite relevant to our discussion (not that it would
add anything but if you're interested in these things you'd probably be
interested to at last know about D).

  apart from the type/precondition/design by contract stuff this is what
cought my eye:

  int[char[]] dictionary;

  as far as I can tell it creates an array of integers indexed by arrays
of chars (btw arrays of chars have their length checked:-)

  anyway, since this is already longer OT thread than neccessary I guess
this is the end from my side, unless there's something extraordinary in
subsequent messages...

	erik



Reply to: