Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Re: C scope and struct definitions

Reply
Thread Tools

Re: C scope and struct definitions

 
 
Eric Sosman
Guest
Posts: n/a
 
      06-24-2012
On 6/23/2012 8:57 PM, James Kuyper wrote:
> On 06/23/2012 07:54 PM, Eric Sosman wrote:
>> [...]
>> A consequence of "What happens in prototype stays in prototype"
>> is that *all* in-prototype identifiers' scopes are limited to the
>> prototype itself. Yes, it leads to a useless construct -- but have
>> you got a usable alternative?

>
> Two:
> C++ way: prohibit definition of types in there parameter list of a
> function declaration.


I'm not a C++ lawyer (nor even a C++ fluent speaker (although I
have "C++ Readability," go figure)), but "no type declarations in
function declarations" seems awfully restrictive:

int main(int argc, char **argv) // BZZZZT!

What must one do instead?

typedef char **charStarStar;
int main(int argc, charStarStar argv)

? But, as I say, I don't speak That Other Language, and maybe I've
read more into your synopsis than was actually present.

> Useful alternative: give types defined in a function's parameter list
> the same scope as the function's declaration, rather than function
> prototype scope.


I'd worked up a nice reductio ad absurdum, and then realized that
you meant something other than what you'd said: You said "same scope
as the function's *declaration*," but you meant "same scope as the
function's *identifier*." I dunno: Might be reasonable, might have
unwelcome consequences in corner cases, might disable some corner
cases that are legitimate now but Ought To Be Banned (Just Think Of
The Children!), ... Needs more thought than my graying gray cells
can muster.

--
Eric Sosman
http://www.velocityreviews.com/forums/(E-Mail Removed)d


 
Reply With Quote
 
 
 
 
Keith Thompson
Guest
Posts: n/a
 
      06-24-2012
(E-Mail Removed) (Alan Curry) writes:
> In article <js5l0m$64l$(E-Mail Removed)>,
> Eric Sosman <(E-Mail Removed)> wrote:
>>On 6/23/2012 6:06 PM, Alan Curry wrote:
>>> In article <js32rk$siv$(E-Mail Removed)>,
>>> Eric Sosman <(E-Mail Removed)> wrote:
>>>> On 6/22/2012 6:40 PM, Alan Curry wrote:
>>>>> But is the compiler right for a real reason, or is it just a
>>>>> continuation of a historical accident? Why would you ever want
>>>>> this behavior?
>>>>
>>>> The Rationale sheds no light my tired old eyes can see. You
>>>> are welcome to read it for yourself. (Also, if you think the
>>>> normative text of the formal definition of the C language does not
>>>> qualify as "a real reason," well ...)
>>>
>>> The standard was supposed to codify existing practice. A real reason
>>> would have to come from before standardization. Was there a real
>>> reason for the existence of such a small, useless scope?

>>
>> Note that existing practice had no notion of prototypes at all,
>>so the issue of "prototype scope" simply didn't exist. (The ANSI
>>Standard invented other things new to the language, too: `void',
>>for example.)
>>
>> But once you've decided to declare a function with a prototype,
>>what scope should any identifiers in the prototype have? It seems
>>pretty clear you don't want them leaking outside, else
>>
>> void foo(char *p);
>> void bar(double *p);
>>
>>... wouldn't compile, because of the conflicting declarations of `p'.
>>I suggest that would have been untenable.

>
> Those names should simply be omitted, and it would be a good thing if they
> weren't allowed either. They serve no purpose and cause problems in header
> files when one header defines a macro that another header uses as an argument
> name in a prototype.
>
> We are allowed to use the intelligent comment markers /* */ in C, not just
> the dumb // to-end-of-line kind, so you can say
>
> void f(char * /*p*/, double * /*q*/);
>
> if the parameter names are meant to be documentation.


Personally, I like having names for parameters in function declarations,
though I'm not pleased that they're ignored. My own preference would be
to make the names mandatory, and to require them to match the names used
in the function's definition.

So neither of is 100% satisfied with the way C is defined. I don't know
of anyone who is.

(I disagree with your characterization of // comments as "dumb", but I
won't get into that.)

> Anyway, putting type names and variable names into a single category and
> calling them "identifiers" is a false generalization. It works at the
> technical level for the compiler implementor I guess, but besides that what's
> the reason for lumping them together and insisting that they behave the same?
> If you can't explain it without the word "identifier" then there is no
> reason, it's just a thought process that's being misled by a bit of escaped
> compiler-writer's jargon.


I'd say it's a perfectly valid generalization. They *are* both
identifiers, and they follow the same scope rules.

You advocate treating type names as a special case with different scope
rules than other identifiers. That's a valid preference, but not one
that I share -- and not one that's consistent with C as it's currently
defined.

>>> I don't think we'd be losing anything if those declarations were simply
>>> illegal. Declare your structs before your functions. They aren't variables.

>>
>> I'm glad the Standard didn't take your view. While I'll admit
>>that function-specific types are not all that common, I'll maintain
>>that they are extremely useful. Most often, there's an ad-hoc
>>table of some kind to assist a function in the performance of its
>>work: Maybe an association of states with their capitols, or ranges
>>of `x' where a rational function/Chebyshev approximation/continued
>>fraction is the preferred computation method. Whatever it is, if
>>it's specific to the operation of one function I see *no* reason to
>>inflict it on others.

>
> The same could be said for a function that's only called by one other
> function. Should we have nested functions then?


Many languages do have nested functions. What tends to make them
complicated is the need to define rules for accessing objects defined
in an outer function. I wouldn't strongly object to adding nested
functions to C (and gcc supports them as an extension), but I don't
think they're all that important; we've gotten along without them
for a very long time.

[...]

> Variable scopes make sense because the object named by the variable doesn't
> exist until the function is called. A type isn't an object.


Are you conflating scope and lifetime?

[...]

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
 
 
 
James Kuyper
Guest
Posts: n/a
 
      06-24-2012
On 06/23/2012 10:11 PM, Eric Sosman wrote:
> On 6/23/2012 8:57 PM, James Kuyper wrote:
>> On 06/23/2012 07:54 PM, Eric Sosman wrote:
>>> [...]
>>> A consequence of "What happens in prototype stays in prototype"
>>> is that *all* in-prototype identifiers' scopes are limited to the
>>> prototype itself. Yes, it leads to a useless construct -- but have
>>> you got a usable alternative?

>>
>> Two:
>> C++ way: prohibit definition of types in there parameter list of a
>> function declaration.

>
> I'm not a C++ lawyer (nor even a C++ fluent speaker (although I
> have "C++ Readability," go figure)), but "no type declarations in
> function declarations" seems awfully restrictive:
>
> int main(int argc, char **argv) // BZZZZT!


I said "type definition", not type declaration. Neither int nor char**
were defined in that declaration, they were only specified as the types
of the corresponding parameters. They aren't identifiers, they don't
have a scope associated with them. Types that have scoped identifiers
that can be defined by user code include struct, union, and enum types.

>> Useful alternative: give types defined in a function's parameter list
>> the same scope as the function's declaration, rather than function
>> prototype scope.

>
> I'd worked up a nice reductio ad absurdum, and then realized that
> you meant something other than what you'd said: You said "same scope
> as the function's *declaration*," but you meant "same scope as the
> function's *identifier*." I dunno: Might be reasonable, might have
> unwelcome consequences in corner cases, might disable some corner
> cases that are legitimate now but Ought To Be Banned (Just Think Of
> The Children!), ... Needs more thought than my graying gray cells
> can muster.


Yes, think on it. Function declarations that would be affected by this
suggestion are useless, so I don't see how it could break existing
working code. Other kinds of unwelcome consequences are certainly
possible, of course.
--
James Kuyper
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      06-24-2012
Eric Sosman <(E-Mail Removed)> writes:
> On 6/23/2012 8:57 PM, James Kuyper wrote:

[...]
>> Two:
>> C++ way: prohibit definition of types in there parameter list of a
>> function declaration.

>
> I'm not a C++ lawyer (nor even a C++ fluent speaker (although I
> have "C++ Readability," go figure)), but "no type declarations in
> function declarations" seems awfully restrictive:
>
> int main(int argc, char **argv) // BZZZZT!
>
> What must one do instead?
>
> typedef char **charStarStar;
> int main(int argc, charStarStar argv)
>
> ? But, as I say, I don't speak That Other Language, and maybe I've
> read more into your synopsis than was actually present.


I think the restriction in C++ is that you can't define a new type name
(either a typedef name or a tag) in a prototype or as a return type.
"char**" is, in some sense, an existing type, not a new one.

I haven't found the rule in the C++ standard that states this
explicitly, but the annex that describes incompatibilities between C and
C++ mentions it.

For example, this:

void f( struct S { int a; } arg ) {}

is valid in C, but invalid in C++. (I'd say it's poor style in C.)

[...]

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Alan Curry
Guest
Posts: n/a
 
      06-24-2012
In article <(E-Mail Removed)>,
Keith Thompson <(E-Mail Removed)> wrote:
>(E-Mail Removed) (Alan Curry) writes:
>
>> Anyway, putting type names and variable names into a single category and
>> calling them "identifiers" is a false generalization. It works at the
>> technical level for the compiler implementor I guess, but besides that what's
>> the reason for lumping them together and insisting that they behave the same?
>> If you can't explain it without the word "identifier" then there is no
>> reason, it's just a thought process that's being misled by a bit of escaped
>> compiler-writer's jargon.

>
>I'd say it's a perfectly valid generalization. They *are* both
>identifiers, and they follow the same scope rules.


They "are" both identifiers because the word "identifier" has been defined
that way. This is a circular argument. It doesn't prove that they belong
together in a class, just that they have been forced into one and an awkward
name has been slapped on it.

>
>You advocate treating type names as a special case with different scope
>rules than other identifiers. That's a valid preference, but not one
>that I share -- and not one that's consistent with C as it's currently
>defined.


More like no scope rules at all. Just a global table of types. (Global within
a single run of the compiler). Any time a new struct tag is seen, just add it
to the table and leave it there until the compiler exits. A type has an
existence inherently outside of any function because types are more
fundamental than functions.

>>
>> The same could be said for a function that's only called by one other
>> function. Should we have nested functions then?

>
>Many languages do have nested functions. What tends to make them
>complicated is the need to define rules for accessing objects defined
>in an outer function. I wouldn't strongly object to adding nested
>functions to C (and gcc supports them as an extension), but I don't
>think they're all that important; we've gotten along without them
>for a very long time.


That complication (closures) is a good reason to want nested functions. It
can be emulated without help from the compiler, but not easily. What's the
corresponding reason for wanting struct definitions inside a function?

>
>[...]
>
>> Variable scopes make sense because the object named by the variable doesn't
>> exist until the function is called. A type isn't an object.

>
>Are you conflating scope and lifetime?
>


Are you seriously saying they aren't (or shouldn't be) closely tied together?

--
Alan Curry
 
Reply With Quote
 
Alan Curry
Guest
Posts: n/a
 
      06-24-2012
In article <js5rl3$5pf$(E-Mail Removed)>,
Eric Sosman <(E-Mail Removed)> wrote:
>On 6/23/2012 8:56 PM, Alan Curry wrote:
>> In article <js5l0m$64l$(E-Mail Removed)>,

>
>> Anyway, putting type names and variable names into a single category and
>> calling them "identifiers" is a false generalization.

>
> If type names are somehow segregated from names-of-other-things,
>does that mean
>
> double int = 42;
> long * double void(short long);
> struct struct { long *union; char enum; };
>
>... are to your liking?


That would depend on whether it adds any conflicts to the grammar. If not, go
for it. We already allow this:

struct foo { int i; };
struct bar { short x,y; };
typedef struct bar bar;
static struct foo foo(bar foo, bar bar) { }

although it doesn't look very good. But this:

int stat(const char *, struct stat *);

has been a respectable function for a long time.

>
> (In my early youth I was weaned on a language that had no
>reserved words at all, a language in which `DO 10 I = (1 , 10)'
>was perfectly legal and *not* a loop construct. For a while I
>esteemed this as a sort of Purity. I got over it.)


I had the opposite of that experience, CBM BASIC. You can't have a variable
name that contains a keyword as a substring, because keywords are recognized
regardless of the lack of spacing around them. Luckily there are only 2
significant characters in a variable name so you'd never have a problem
unless you flamboyantly extended your variable names with insignificant
characters.

>
> But, hey: Back to the beginning. You asked whether a compiler
>that obeyed 6.2.1p4 did so quote "for a real reason" end quote.
>The answer to your question is "Yes," because 6.2.1p4 dictates
>how the compiler must behave. Debate about whether 6.2.1p4 ought
>to have said something else should be between you and X3J11, not
>between you and me.


Standards aren't reasons at all. Official rationale is supplied for a few
things, the rest is just a record of decisions made and the reasons are found
elsewhere in history.

--
Alan Curry
 
Reply With Quote
 
Jens Gustedt
Guest
Posts: n/a
 
      06-24-2012
Am 24.06.2012 07:40, schrieb Alan Curry:
>> Are you conflating scope and lifetime?

>
> Are you seriously saying they aren't (or shouldn't be) closely tied together?


Hm, your question is vague, I don't see the point you want to make.

Lifetime is a property of objects that is determined at run time.
Objects, in particular those that are allocated through malloc and
friends, don't have a sensible notion of scope.

Scope is a property of identifiers that only makes sense at
compilation time. Identifiers don't have lifetime at all.

Jens
 
Reply With Quote
 
Jens Gustedt
Guest
Posts: n/a
 
      06-24-2012
Am 24.06.2012 02:57, schrieb James Kuyper:
> On 06/23/2012 07:54 PM, Eric Sosman wrote:
>> A consequence of "What happens in prototype stays in prototype"
>> is that *all* in-prototype identifiers' scopes are limited to the
>> prototype itself. Yes, it leads to a useless construct -- but have
>> you got a usable alternative?

>
> Two:
> C++ way: prohibit definition of types in there parameter list of a
> function declaration.
>
> Useful alternative: give types defined in a function's parameter list
> the same scope as the function's declaration, rather than function
> prototype scope.


I don't think that this alternative would buy us much and would add up
to confusion. Remember that struct can only be declared once, so the
definition of such a function then must look (syntactically) different
from the prototype since it can't redeclare the struct.

There can only be some marginal code base that uses struct definitions
in prototypes directly. They are basically useless. So the C++
treatment would be a possible addition to C.

Jens
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      06-24-2012
On 06/24/2012 04:56 AM, Jens Gustedt wrote:
> Am 24.06.2012 02:57, schrieb James Kuyper:
>> On 06/23/2012 07:54 PM, Eric Sosman wrote:
>>> A consequence of "What happens in prototype stays in prototype"
>>> is that *all* in-prototype identifiers' scopes are limited to the
>>> prototype itself. Yes, it leads to a useless construct -- but have
>>> you got a usable alternative?

>>
>> Two:
>> C++ way: prohibit definition of types in there parameter list of a
>> function declaration.
>>
>> Useful alternative: give types defined in a function's parameter list
>> the same scope as the function's declaration, rather than function
>> prototype scope.

>
> I don't think that this alternative would buy us much and would add up
> to confusion. Remember that struct can only be declared once, so the
> definition of such a function then must look (syntactically) different
> from the prototype since it can't redeclare the struct.


Yes, that is a valid point.

> There can only be some marginal code base that uses struct definitions
> in prototypes directly. They are basically useless. So the C++
> treatment would be a possible addition to C.


I've no objection to adopting the C++ approach, just pointing out that
there are workable alternatives. The current rules allow a declaration
that is useless for some rather subtle reasons, and I don't think that's
a good idea.
--
James Kuyper
 
Reply With Quote
 
Tim Rentsch
Guest
Posts: n/a
 
      06-24-2012
(E-Mail Removed) (Alan Curry) writes:

> In article <js2buv$evv$(E-Mail Removed)>,
> Eric Sosman <(E-Mail Removed)> wrote:
>>On 6/22/2012 1:30 PM, Kenneth Brody wrote:
>>>
>>> int foo(struct bar *);
>>>
>>> ...
>>>
>>> int foo(struct bar *baz)
>>> {
>>> ...
>>> }
>>>
>>> The compiler decided that the "struct bar" in one place was not the same
>>> "struct bar" in the other place.

> [...]
>>
>> The compiler was right. The relevant text is in 6.2.1p4:

>
> But is the compiler right for a real reason, or is it just a continuation of
> a historical accident?


Surely not a historical accident, because prototypes didn't exist
in C before it was standardized.

> Why would you ever want this behavior?
>
> I don't even see why you'd ever want any scope for a struct type other than
> "from here to the end of the file". Types are global things.


To me it would be extremely counterintuitive for a type declared
in a function prototype to "leak out" into the surrounding scope.

Also, the behavior in C probably was chosen to match the behavior
in C++, from whence prototypes were derived. So this is really
a C++ question rather than a C question (1/2 .

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Can *common* struct-members of 2 different struct-types, that are thesame for the first common members, be accessed via pointer cast to either struct-type? John Reye C Programming 28 05-08-2012 12:24 AM
member templated definitions out of class scope George C++ 1 11-08-2007 07:55 PM
scope of struct definitions James Brown C Programming 2 11-04-2006 01:02 PM
Scope in Method Definitions Curt Sampson Ruby 4 04-13-2005 08:35 AM
struct my_struct *p = (struct my_struct *)malloc(sizeof(struct my_struct)); Chris Fogelklou C Programming 36 04-20-2004 08:27 AM



Advertisments