Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.misc > #2178 > unrolled thread
| Started by | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| First post | 2014-05-05 08:47 +0100 |
| Last post | 2014-05-05 19:08 -0500 |
| Articles | 20 on this page of 64 — 9 participants |
Back to article view | Back to comp.lang.misc
A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-05 08:47 +0100
Re: A good subset of C "BartC" <bc@freeuk.com> - 2014-05-05 10:56 +0100
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-05 19:41 +0100
Re: A good subset of C "BartC" <bc@freeuk.com> - 2014-05-05 21:08 +0100
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-05 21:58 +0100
Re: A good subset of C "BartC" <bc@freeuk.com> - 2014-05-05 22:55 +0100
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-06 00:01 +0100
Re: A good subset of C "BartC" <bc@freeuk.com> - 2014-05-06 00:44 +0100
Re: A good subset of C "BartC" <bc@freeuk.com> - 2014-05-06 09:45 +0100
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-05 07:33 -0400
Re: A good subset of C "BartC" <bc@freeuk.com> - 2014-05-05 19:14 +0100
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-05 20:12 +0100
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-05 18:57 -0400
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-07 11:55 +0100
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-07 19:04 -0400
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-08 10:14 +0100
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-08 07:35 -0400
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-08 16:22 +0100
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-09 16:45 -0400
Re: A good subset of C "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> - 2014-05-10 09:04 +0200
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-10 16:30 -0400
Re: A good subset of C "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> - 2014-05-11 11:59 +0200
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-11 11:06 -0400
Re: A good subset of C Kaz Kylheku <kaz@kylheku.com> - 2014-05-12 00:26 +0000
Re: A good subset of C "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> - 2014-05-12 09:54 +0200
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-12 20:01 -0400
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-14 17:45 +0100
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-14 18:11 -0400
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-14 23:54 +0100
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-14 19:43 -0400
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-17 18:00 +0100
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-17 16:00 -0400
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-17 22:17 +0100
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-17 19:58 -0400
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-18 07:59 +0100
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-18 13:10 -0400
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-19 00:54 +0100
Re: A good subset of C Andy Walker <news@cuboid.co.uk> - 2014-05-15 01:31 +0100
Re: A good subset of C BGB <cr88192@hotmail.com> - 2014-05-14 23:43 -0500
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-17 18:38 +0100
Re: A good subset of C Ian Collins <ian-news@hotmail.com> - 2014-05-25 11:04 +1200
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-24 20:36 -0400
Re: A good subset of C Ian Collins <ian-news@hotmail.com> - 2014-05-25 12:53 +1200
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-24 21:34 -0400
Re: A good subset of C Ian Collins <ian-news@hotmail.com> - 2014-05-25 14:11 +1200
Re: A good subset of C Kaz Kylheku <kaz@kylheku.com> - 2014-05-25 06:47 +0000
Re: A good subset of C Kaz Kylheku <kaz@kylheku.com> - 2014-05-25 06:43 +0000
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-05 20:59 +0100
Re: A good subset of C "BartC" <bc@freeuk.com> - 2014-05-05 22:28 +0100
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-05 18:57 -0400
Re: A good subset of C "BartC" <bc@freeuk.com> - 2014-05-06 00:26 +0100
Re: A good subset of C George Neuner <gneuner2@comcast.net> - 2014-05-06 14:21 -0400
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-07 15:43 +0100
Re: A good subset of C George Neuner <gneuner2@comcast.net> - 2014-05-07 16:03 -0400
Re: A good subset of C "BartC" <bc@freeuk.com> - 2014-05-07 21:31 +0100
Re: A good subset of C BGB <cr88192@hotmail.com> - 2014-05-07 15:41 -0500
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-05 18:46 -0400
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-06 00:42 +0100
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-06 06:48 -0400
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-07 15:40 +0100
Re: A good subset of C "Rod Pemberton" <dont_use_email@xnothavet.cqm> - 2014-05-08 06:50 -0400
Re: A good subset of C "James Harris" <james.harris.1@gmail.com> - 2014-05-08 15:43 +0100
Re: A good subset of C George Neuner <gneuner2@comcast.net> - 2014-05-08 14:41 -0400
Re: A good subset of C BGB <cr88192@hotmail.com> - 2014-05-05 19:08 -0500
Page 1 of 4 [1] 2 3 4 Next page →
| From | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| Date | 2014-05-05 08:47 +0100 |
| Subject | A good subset of C |
| Message-ID | <lk7flm$m95$1@dont-email.me> |
In two recent threads we discussed good and bad points about C. Some good things were mentioned but the focus was mainly on the points that we would like to fix. I got to wondering if there could be considered a "good" subset of C - i.e. of the whole programming approach including language, preprocessor, standard library etc. The subset should be much easier to compile than full C but it does not need to do everything that a programming language should; things could be added. Put another way, if you were designing a new language based on C what parts of C would you keep in? James
[toc] | [next] | [standalone]
| From | "BartC" <bc@freeuk.com> |
|---|---|
| Date | 2014-05-05 10:56 +0100 |
| Message-ID | <XfJ9v.209855$X41.111305@fx15.am4> |
| In reply to | #2178 |
"James Harris" <james.harris.1@gmail.com> wrote in message news:lk7flm$m95$1@dont-email.me... > I got to wondering if there could be considered a "good" subset of C - > i.e. of the whole programming approach including language, preprocessor, > standard library etc. > > The subset should be much easier to compile than full C but it does not > need to do everything that a programming language should; things could be > added. That depends on your aims for the subset. If any sort of compatibility with the vast range of existing C sources is needed, then your hands are pretty much tied and you will have to leave nearly everything in (ie. just re-implement another C compiler). For example, if you wanted to be able to just write #include <windows.h> or #include <stdafx.h> in the new language, or make use of any third party libraries where normally you'd just include a bunch of headers, then I can't see any new language in managing to be much different. A few additions perhaps, but then it would be a superset (and not a simple project either). If you are only going to write new programs, then you can probably get away with leaving out troublesome features; most of the macro pre-processor for example (which I think this has had a negative influence on the language). > Put another way, if you were designing a new language based on C what > parts of C would you keep in? For a language at the same level, then the basics are going to be the same, in terms of data-types, statements and expressions. But every language is going to have these; what unique features does C have that you want to replicate? Probably not many! (Actually, I've adopted a few minor features from C over the years, some of which I'd disliked at first: * '0x123' style for hex numbers * '()' to indicate a function call with no parameters * I might adopt auto-derefs for function names and array accesses * Using anonymous structs and unions to control layout in structs (instead of explicit offsets) * I'm thinking of having case-sensitive identifiers * And having separate treatment of statements and expressions (previously these were treated the same; it's better to have them distinct, even though gcc has an extension to mix them up again!)) -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| Date | 2014-05-05 19:41 +0100 |
| Message-ID | <lk8m0i$acg$1@dont-email.me> |
| In reply to | #2181 |
"BartC" <bc@freeuk.com> wrote in message news:XfJ9v.209855$X41.111305@fx15.am4... > "James Harris" <james.harris.1@gmail.com> wrote in message > news:lk7flm$m95$1@dont-email.me... > >> I got to wondering if there could be considered a "good" subset of C - >> i.e. of the whole programming approach including language, preprocessor, >> standard library etc. >> >> The subset should be much easier to compile than full C but it does not >> need to do everything that a programming language should; things could be >> added. > > That depends on your aims for the subset. If any sort of compatibility > with the vast range of existing C sources is needed, then your hands are > pretty much tied and you will have to leave nearly everything in (ie. just > re-implement another C compiler). I wasn't thinking of compatibility with existing source code. As you say, that would just end up in having to do what any C compiler does. > For example, if you wanted to be able to just write #include <windows.h> > or #include <stdafx.h> in the new language, or make use of any third party > libraries where normally you'd just include a bunch of headers, then I > can't see any new language in managing to be much different. A few > additions perhaps, but then it would be a superset (and not a simple > project either). > > If you are only going to write new programs, then you can probably get > away with leaving out troublesome features; most of the macro > pre-processor for example (which I think this has had a negative influence > on the language). The preprocessor is a bit of an anomaly. Expressions like sizeof() would be useful but they cannot be used in the preprocessor as they are only valid later in the compilation. Could the most useful features of the preprocessor be integrated into the language? It might be better for the compiler to make additional passes. Then all of the syntax and data for a preprocessing-type step could be the same as that used in the compilation - possibly. >> Put another way, if you were designing a new language based on C what >> parts of C would you keep in? > > For a language at the same level, then the basics are going to be the > same, in terms of data-types, statements and expressions. But every > language is going to have these; what unique features does C have that you > want to replicate? Probably not many! That might be good. The simpler the better. > (Actually, I've adopted a few minor features from C over the years, some > of which I'd disliked at first: > > * '0x123' style for hex numbers > * '()' to indicate a function call with no parameters > * I might adopt auto-derefs for function names and array accesses That doesn't sound like a big issue but I don't understand what you had in mind. > * Using anonymous structs and unions to control layout in structs (instead > of explicit offsets) Could you post a small example of that? > * I'm thinking of having case-sensitive identifiers > * And having separate treatment of statements and expressions (previously > these were treated the same; it's better to have them distinct, even > though gcc has an extension to mix them up again!)) Doesn't C treat statements as expressions anyway? James
[toc] | [prev] | [next] | [standalone]
| From | "BartC" <bc@freeuk.com> |
|---|---|
| Date | 2014-05-05 21:08 +0100 |
| Message-ID | <2dS9v.221970$t73.184410@fx14.am4> |
| In reply to | #2186 |
"James Harris" <james.harris.1@gmail.com> wrote in message
news:lk8m0i$acg$1@dont-email.me...
> "BartC" <bc@freeuk.com> wrote in message
> news:XfJ9v.209855$X41.111305@fx15.am4...
>> If you are only going to write new programs, then you can probably get
>> away with leaving out troublesome features; most of the macro
>> pre-processor for example (which I think this has had a negative
>> influence on the language).
>
> The preprocessor is a bit of an anomaly. Expressions like sizeof() would
> be useful but they cannot be used in the preprocessor as they are only
> valid later in the compilation. Could the most useful features of the
> preprocessor be integrated into the language? It might be better for the
> compiler to make additional passes. Then all of the syntax and data for a
> preprocessing-type step could be the same as that used in the
> compilation - possibly.
I've done without a pre-processor for decades. But then I haven't needed to
create the same source code for lots of different systems and
configurations. Using it for such purposes doesn't generate the best-looking
source code however. It might be better to look at alternative approaches
for that.
I've always had simple text-substitution macros, but without parameters:
define tword = tu32 # create alias
define inta = (fullcmd.opnds[1])
These don't need a separate pass. But they have the usual problems of having
file-scope. I don't use them to define constants, there are proper
statements for those.
I have recently added conditional compilation, but only because I was
porting C-derived code that used it and it was easier to add it.
(There are few other directives that are used during tokenising, but they
don't really count as a 'preprocessor', such as include and strinclude
(which turns a file into a string constant).)
>> (Actually, I've adopted a few minor features from C over the years, some
>> of which I'd disliked at first:
>>
>> * '0x123' style for hex numbers
>> * '()' to indicate a function call with no parameters
>> * I might adopt auto-derefs for function names and array accesses
>
> That doesn't sound like a big issue but I don't understand what you had in
> mind.
In C you can write fnptr(a,b,c) instead of (*fnptr)(a,b,c), and axptr[i]
instead of (*axptr)[i] (probably a good thing too because the parentheses
needed add clutter).
I currently have to write fnptr^(a,b,c) and axptr^[i]; not as bad as the C
would be, but there can be advantages in hiding the indirect nature of the
function or array pointers.
>> * Using anonymous structs and unions to control layout in structs
>> (instead of explicit offsets)
>
> Could you post a small example of that?
I used to write code like this:
type varrec = record
word tag
byte copy
byte alloc
byte celemtype @alloc
long tagx @tag
....
(Where word=16 bits, long=32 bits). This defines three fields totalling
32-bits, an alias for the 'alloc' field, and a way of accessing all 32-bits
at once using the 'tagx' field.
In C the above would be written like this:
typedef struct _varrec {
union {
struct {
u16 tag;
u8 copy;
union {
u8 alloc;
u8 celemtype;
};
};
u32 tagx;
};
Actually, my version doesn't look too bad in comparison! But in order to
target C, it was easier to change to this style (than use various tricks,
type-punning etc, to achieve the same).
>> * I'm thinking of having case-sensitive identifiers
>> * And having separate treatment of statements and expressions (previously
>> these were treated the same; it's better to have them distinct, even
>> though gcc has an extension to mix them up again!))
>
> Doesn't C treat statements as expressions anyway?
I think you can write an expression where a statement might be (eg.
assignment or call), but not a statement where an expression is expected
(eg. fn(a,b,for(i=0;i<10;++i)).
But even this lets a few odd-looking constructs through; this is legal:
a+b;
but is likely a mistake. By separating the two completely, it was much
easier to pick up errors (especially writing a=b instead of a:=b).
(Previously I really could write an entire program almost in place of a
parameter or index, or on the left or right side of an assignment. It worked
fine, but dropped it when I was experimenting with source-to-source
translators (eg. having C or Python as output).
It makes for a more conventional language, but I haven't reinstated that and
haven't missed it.)
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| Date | 2014-05-05 21:58 +0100 |
| Message-ID | <lk8u1q$abe$1@dont-email.me> |
| In reply to | #2190 |
"BartC" <bc@freeuk.com> wrote in message news:2dS9v.221970$t73.184410@fx14.am4... ... >> The preprocessor is a bit of an anomaly. Expressions like sizeof() would >> be useful but they cannot be used in the preprocessor as they are only >> valid later in the compilation. Could the most useful features of the >> preprocessor be integrated into the language? It might be better for the >> compiler to make additional passes. Then all of the syntax and data for a >> preprocessing-type step could be the same as that used in the >> compilation - possibly. > > I've done without a pre-processor for decades. But then I haven't needed > to > create the same source code for lots of different systems and > configurations. Using it for such purposes doesn't generate the > best-looking > source code however. It might be better to look at alternative approaches > for that. Source code that contains lots of #if ... #else ... #endif blocks can become hard to maintain. It is easy to 'patch' some code for different circumstances with conditional compilation but I'm not sure that as a solution it scales well. What about the preprocessor's pulling in header files, though? Because C is a static language the compiler needs to know some things at compile time and, when interfacing with other pieces of code it is traditional for a header file to be created describing interface info about the other module. Do you have a different way to support separate compilation of modules that interface with each other? ... >> Doesn't C treat statements as expressions anyway? > > I think you can write an expression where a statement might be (eg. > assignment or call), but not a statement where an expression is expected > (eg. fn(a,b,for(i=0;i<10;++i)). > > But even this lets a few odd-looking constructs through; this is legal: > > a+b; > > but is likely a mistake. By separating the two completely, it was much > easier to pick up errors (especially writing a=b instead of a:=b). Yes. b() is obviously OK but a + b() is a bit odd. Of course, b has to be called because it might have an effect but the addition of a seems to be superfluous. James
[toc] | [prev] | [next] | [standalone]
| From | "BartC" <bc@freeuk.com> |
|---|---|
| Date | 2014-05-05 22:55 +0100 |
| Message-ID | <8PT9v.293553$te5.172198@fx13.am4> |
| In reply to | #2192 |
"James Harris" <james.harris.1@gmail.com> wrote in message news:lk8u1q$abe$1@dont-email.me... > "BartC" <bc@freeuk.com> wrote in message >> I've done without a pre-processor for decades. > What about the preprocessor's pulling in header files, though? Because C > is a static language the compiler needs to know some things at compile > time and, when interfacing with other pieces of code it is traditional for > a header file to be created describing interface info about the other > module. Do you have a different way to support separate compilation of > modules that interface with each other? I have an import system that I used for dynamic modules, and that worked well. I've now tried to use it for static code. It doesn't work quite as well, but well enough to keep it in (and considerably better than having to mess around with C-style headers). It works something like this. Suppose your source language is called A, and file extensions are ".a". Then: * In a source module lib.a, all names are local (non-exported) by default * To export a name, you place 'global' in front of the declaration. This applies to functions, types, variables, named constants and enums. * When compiled, an automatic exports file is generated, called lib.ax, containing the exported names in a source format than can be included by another module. * When another module, such as prog.a, needs to use module lib, you just write: import lib and this will automatically include the lib.ax file (You can also write directly: 'include "lib.ax"', but that doesn't check whether lib has already been processed as 'import lib' does.) * Inside lib.ax, exported names are defined inside a block (importmodule lib = ..declarations ... end) which also bestows the namespace 'lib' on these names. But I don't use that much. It sounds great, but there are a few problems: * The module structure must form a hierarchy, which creates problems with modules that mutually import from each other. This is good discipline in getting your program structured neatly, but there are still a few declarations that must done manually (and declared as external). * The order of compilation can be critical; the module at the top of the tree should be compiled first, when it changes. An IDE can sort this out, or I just do a couple of 'compile-all' from time to time (each takes <2 seconds on my largest project). Since I usually only work on a small number of modules, most of the time it's not an issue. >> But even this lets a few odd-looking constructs through; this is legal: >> >> a+b; >> >> but is likely a mistake. By separating the two completely, it was much >> easier to pick up errors (especially writing a=b instead of a:=b). > > Yes. > > b() > > is obviously OK but > > a + b() > > is a bit odd. Of course, b has to be called because it might have an > effect but the addition of a seems to be superfluous. I used to write code like this when I used an inline assembler a lot: a+b would evaluate a+b and leave the result in EAX. It was handy! So I might have to stick a keyword in front to turn it into a statement: eval a+b -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| Date | 2014-05-06 00:01 +0100 |
| Message-ID | <lk959c$uag$1@dont-email.me> |
| In reply to | #2195 |
"BartC" <bc@freeuk.com> wrote in message news:8PT9v.293553$te5.172198@fx13.am4... > "James Harris" <james.harris.1@gmail.com> wrote in message > news:lk8u1q$abe$1@dont-email.me... >> "BartC" <bc@freeuk.com> wrote in message > >>> I've done without a pre-processor for decades. > >> What about the preprocessor's pulling in header files, though? Because C >> is a static language the compiler needs to know some things at compile >> time and, when interfacing with other pieces of code it is traditional >> for >> a header file to be created describing interface info about the other >> module. Do you have a different way to support separate compilation of >> modules that interface with each other? > > I have an import system that I used for dynamic modules, and that worked > well. I've now tried to use it for static code. It doesn't work quite as > well, but well enough to keep it in (and considerably better than having > to > mess around with C-style headers). > > It works something like this. Suppose your source language is called A, > and > file extensions are ".a". Then: > > * In a source module lib.a, all names are local (non-exported) by default > > * To export a name, you place 'global' in front of the declaration. This > applies to functions, types, variables, named constants and enums. > > * When compiled, an automatic exports file is generated, called lib.ax, > containing the exported names in a source format than can be included by > another module. > > * When another module, such as prog.a, needs to use module lib, you just > write: > > import lib > > and this will automatically include the lib.ax file (You can also write > directly: 'include "lib.ax"', but that doesn't check whether lib has > already > been processed as 'import lib' does.) > > * Inside lib.ax, exported names are defined inside a block (importmodule > lib > = ..declarations ... end) which also bestows the namespace 'lib' on these > names. But I don't use that much. > > It sounds great, but there are a few problems: It does sound good, thanks. I think I can use something like that. > * The module structure must form a hierarchy, which creates problems with > modules that mutually import from each other. This is good discipline in > getting your program structured neatly, but there are still a few > declarations that must done manually (and declared as external). I'm not sure that a hierarchy is needed. To make an example, say there were two source files, P.a and Q.a and each referred to exports from the other so that a hierarchy is impossible. Let's say we try to compile P first. When the compiler is compiling P and sees an import referring to Q it could: 1. Check for a file Q.ax which is newer than Q.a. If there is not, scan Q.a for exports and build an up-to-date Q.ax without going through a full compile of Q.a. 2. Use Q.ax to compile P.a including preparing P.ax. If and when the compiler is told to compile Q.a it goes through the same process but finds P.ax to be newer than P.a. Would that work? James
[toc] | [prev] | [next] | [standalone]
| From | "BartC" <bc@freeuk.com> |
|---|---|
| Date | 2014-05-06 00:44 +0100 |
| Message-ID | <UnV9v.259259$vB1.224540@fx36.am4> |
| In reply to | #2199 |
"James Harris" <james.harris.1@gmail.com> wrote in message news:lk959c$uag$1@dont-email.me... > "BartC" <bc@freeuk.com> wrote in message >> I have an import system that I used for dynamic modules, and that worked >> well. I've now tried to use it for static code. It doesn't work quite as >> well, but well enough to keep it in (and considerably better than having >> to >> mess around with C-style headers). > It does sound good, thanks. I think I can use something like that. > >> * The module structure must form a hierarchy, which creates problems with >> modules that mutually import from each other. This is good discipline in >> getting your program structured neatly, but there are still a few >> declarations that must done manually (and declared as external). > > I'm not sure that a hierarchy is needed. To make an example, say there > were two source files, P.a and Q.a and each referred to exports from the > other so that a hierarchy is impossible. Let's say we try to compile P > first. This is exactly the problem that can occur! (For example, if P,Q were originally one file that are now split up.) > When the compiler is compiling P and sees an import referring to Q it > could: > > 1. Check for a file Q.ax which is newer than Q.a. If there is not, scan > Q.a for exports and build an up-to-date Q.ax without going through a full > compile of Q.a. > 2. Use Q.ax to compile P.a including preparing P.ax. Suppose that neither P.ax and Q.ax yet exist. So when compiling P, it can't do: import Q, so a bunch of definitions are missing. Maybe, it can do a partial compile of P to extract the global names, but it is possible that some of those names depend critically on something exported from Q (a type for example, or some constant value). That might not happen; maybe it is just a few global functions from each that need to be collated. But in general, I'm not sure that can be done. To solve this, if you want to use the import system: * Move some critical names in both P and Q into a module common to both (imported by both; modules can contain just data or just declarations). * If there are only a few imports causing trouble, declare them in the traditional manner (as a header file for example) * Or restructure things so that P and Q are not interdependent. This why there are some flaws with this. There was another problem I didn't mention: on one project, instead of just having a single project header file at the top of each module, each module now has a different list of import statements! (These are the first few lines of the main module of my last interpreter: import clib import qclib import pcc_decls import pcc_tables import pcc_support import pcc_win import pcc_loadbc import pcc_loadpc import pcc_memory And this is what the not-quite-C version was: #include "pcc_hdr.h" ) Once it's sorted out, however, creating a new global is a joy: just remember to add 'global' in front, recompile that module, now it is instantly available to all others (that import that module). Also, once structured properly, it is far easier to take, say, pcc_memory above, and use it in another project; that other project just has: import pcc_memory which will pull in whatever modules /it/ needs. -- bartc
[toc] | [prev] | [next] | [standalone]
| From | "BartC" <bc@freeuk.com> |
|---|---|
| Date | 2014-05-06 09:45 +0100 |
| Message-ID | <Ni1av.330914$n%4.305139@fx10.am4> |
| In reply to | #2192 |
"James Harris" <james.harris.1@gmail.com> wrote in message news:lk8u1q$abe$1@dont-email.me... > "BartC" <bc@freeuk.com> wrote in message > Do you have a different way to support separate compilation of modules > that interface with each other? Actually there was another way I used to do this. Still based on include files, and still requiring some names to declared both in their 'home' module and in a header (although this can be partly automated, see below), but still one level of sophistication above C's system: * Generally, such include files were /not/ specified in the modules themselves. * When compiling a module, the compiler was also provided with the name of just one header file * This header file might just consist of a list of includes (normally constructed by an IDE from from files it knows are headers) * This header file is compiled as a separate, outer scope to the main module. (So it was possible to have a name ABC in the header, and override that with a local file-scope name ABC in the module.) There was no namespace system however. * In the header file (or any of its include files), data could be declared, both initialised (tables etc) and not initialised. This data belonged to the header, not to any module. * For the above reason, the header itself forms a separate module that is also compiled (sans header in this case) and linked. * Names in the header don't need global or external attributes; the compiler will know what to apply. So no headers or imports are necessary at all in any module. (Normal include files could be used, but the contents are just treated as though they are part of the module source, using the same scope. Traditional external declarations could be used in the module too.) That language still required 'prototypes' for its functions: local ones for local functions, and global ones in the main header. (Shared variables, type defs, and constants were simply declared once in the header.) With another project that was a thin wrapper around C, the translator (a simple 400-line program) also collated the functions, into local ones and global ones (which had a 'global' prefix), and generated two extra files: a .cl file containing the local prototypes, and a .cx file containing the global/exported ones. The .cl file was simply included in its own module. The .cx file was included in the project header. Any changes to a module's .cx file also sometimes required a 'compile-all'. Anyway, I don't think it's hard to come up with something 'better' that C's system of headers (which are just includes files after all, not really headers with any special significance). -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | "Rod Pemberton" <dont_use_email@xnothavet.cqm> |
|---|---|
| Date | 2014-05-05 07:33 -0400 |
| Message-ID | <op.xfdw11vx6zenlw@localhost> |
| In reply to | #2178 |
On Mon, 05 May 2014 03:47:01 -0400, James Harris <james.harris.1@gmail.com> wrote: > In two recent threads we discussed good and bad points about C. Some good > things were mentioned but the focus was mainly on the points that we > would > like to fix. I got to wondering if there could be considered a "good" > subset > of C - i.e. of the whole programming approach including language, > preprocessor, > standard library etc. > > The subset should be much easier to compile than full C but it does not > need to do everything that a programming language should; things could be > added. > > Put another way, if you were designing a new language based on C what > parts of C would you keep in? > It's really a question of how minimal or how primitive do you want that subset to be. It's useful either way, just a question of how useful. I'd say you need an if statement, one loop statement - while(1), break, switch, curly braces, most of C's math and assignment operators, pointers, functions, ability to take addresses of object &, ability to dereference pointers to data and to call functions *, subscript operator for "arrays" [], structs, typedefs, variables, unsigned char, unsigned long. A few preprocessor directives such as: #include, #if, #endif, #ifdef, #define, would be useful. I'd keep hexadecimal and decimal for number representation. There is little need for octal for numeric representations. There is no need for floats. There is no, or not much, need for goto, continue, unions, or an else statement. There is no need for more than two integer types. One is for characters and the other for integers. There is minimal need of the standard libaries, except <stdio.h>. You may want a few functions from other library include files such as malloc(), free(), exit(), atexit(). While you need "addressof" &, you generally don't need "sizeof" sizeof(), or the "typeof" and "alignof" operations internal to most C compilers. You can definately forget about any GNU C extension. You can eliminate unary operators, pre-dec/increment, most use of the comma operator, the conditional ?: operator, etc. Some of C's operators are redundant or can be expressed using the others, which eliminates the need for them, especially the numerous assignment operators. E.g., 'a+=3' becomes 'a=a+3', 'a->b' becomes '(*a).b', and 'a[b]' becomes '*((a)+(b))'. (So, that's like a lot of them gone ...) Of course, parenthesis just clutter up the code, so, fix that. ;-) For a truly minimalist situation, you can get by without switch, structs, typedefs, malloc, free, exit, atexit. However, the language becomes really annoying without them. Everything must be declared to be allocated, and *everything* is pointer based, i.e., to emulate structs or arrays. Not having a switch means many if statements, etc. You could consider eliminating character escape sequences, e.g., '\n' '\"' etc. That will simply strings. However, you'll have to use 'putc(0x13)' to do '\n' etc. Eliminating an escaped quote will eliminate some parsing issues ... "quote\"escaped" You could consider eliminating 'void' and 'void *'. I.e., go back to using character pointers. Rod Pemberton
[toc] | [prev] | [next] | [standalone]
| From | "BartC" <bc@freeuk.com> |
|---|---|
| Date | 2014-05-05 19:14 +0100 |
| Message-ID | <4yQ9v.196602$t%4.25057@fx04.am4> |
| In reply to | #2183 |
"Rod Pemberton" <dont_use_email@xnothavet.cqm> wrote in message news:op.xfdw11vx6zenlw@localhost... > On Mon, 05 May 2014 03:47:01 -0400, James Harris > There is no, or not much, need for goto, continue, unions, or an else > statement. Without 'else' or 'goto', then programming is not going to be much fun. Here's an example of unstructured C that doesn't use any control flow statements except if and goto, which are always used together: http://pastebin.com/dmceAVhM Without 'goto', then generating 'flat' code like this would be a lot harder. (In terms of complexity, those two add very little to an implementation. In fact a lot of syntax isn't difficult to add so it doesn't make sense to get rid of it) -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| Date | 2014-05-05 20:12 +0100 |
| Message-ID | <lk8nrc$ov4$1@dont-email.me> |
| In reply to | #2183 |
"Rod Pemberton" <dont_use_email@xnothavet.cqm> wrote in message news:op.xfdw11vx6zenlw@localhost... ... >> Put another way, if you were designing a new language based on C what >> parts of C would you keep in? >> > > It's really a question of how minimal or how primitive do you want that > subset to be. It's useful either way, just a question of how useful. > > I'd say you need an if statement, one loop statement - while(1), break, > switch, curly braces, most of C's math and assignment operators, pointers, > functions, ability to take addresses of object &, ability to dereference > pointers to data and to call functions *, subscript operator for > "arrays" [], structs, typedefs, variables, unsigned char, unsigned long. > > A few preprocessor directives such as: #include, #if, #endif, #ifdef, > #define, would be useful. You are probably right but it would be good to drop the preprocessor, if possible, because it is significant to write and a bit of an anomaly. It is like a separate language mixed in with C. But I cannot think how to bring in the definitions of structs (from which field offsets are calculated) without header files. Umm... maybe all structs could be required to be local to the source file which uses them. I'll have to give that some more thought. Enumerated constants could be brought in by other mechanisms such as importing them. Could useful #defines be replaced by constants and/or having multiple passes? Could #if and friends be omitted, for example by including executable tests in the code? ... (snipped your other comments - agreed with) James
[toc] | [prev] | [next] | [standalone]
| From | "Rod Pemberton" <dont_use_email@xnothavet.cqm> |
|---|---|
| Date | 2014-05-05 18:57 -0400 |
| Message-ID | <op.xfesqctt6zenlw@localhost> |
| In reply to | #2187 |
On Mon, 05 May 2014 15:12:47 -0400, James Harris <james.harris.1@gmail.com> wrote: > "Rod Pemberton" <dont_use_email@xnothavet.cqm> wrote in message > news:op.xfdw11vx6zenlw@localhost... > But I cannot think how to bring in the definitions of structs > (from which field offsets are calculated) without header files. Well, I mentioned these: address of - address operator & - part of C sizeof() operator - part of C typeof - part of the compilers alignof - part of the compiler But, I forgot this one: offsetof() - part of C (macro in stddef.h) offsetof() gets the offsets of something, like the element of a struct or union. Look at the macro in stddef.h or Google "offsetof macro". Usually, they cast 0 or NULL as a pointer to a char or void as the starting address of the appropriate type (struct or union), then they subtract that from the address of a component, using the same cast for the starting address, -> for component selection, & address operator for the component's address, and a cast of the address to a pointer to a char or void. If you have a preprocessor, you can use it. If not, I think you'll have to insert an expanded definition everywhere you need it ..., or perhaps implement it within the compiler. The compiler should have the necessary information to do it since it knows the struct or union layout and sizes of everything in it's symbol tables etc. > Could #if and friends be omitted, for example by including > executable tests in the code? #if #endif #ifdef could be replaced by regular if statements, with a flag or variable to indicate which code is active. #define's in the code can be replaced with the value or expanded macro, etc. I don't think there is an easy way to handle #include, except cut-n-paste the entire include ... Rod Pemberton
[toc] | [prev] | [next] | [standalone]
| From | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| Date | 2014-05-07 11:55 +0100 |
| Message-ID | <lkd3fo$2mv$1@dont-email.me> |
| In reply to | #2197 |
"Rod Pemberton" <dont_use_email@xnothavet.cqm> wrote in message news:op.xfesqctt6zenlw@localhost... > On Mon, 05 May 2014 15:12:47 -0400, James Harris > <james.harris.1@gmail.com> wrote: >> "Rod Pemberton" <dont_use_email@xnothavet.cqm> wrote in message >> news:op.xfdw11vx6zenlw@localhost... > >> But I cannot think how to bring in the definitions of structs >> (from which field offsets are calculated) without header files. > > Well, I mentioned these: > address of - address operator & - part of C > sizeof() operator - part of C > typeof - part of the compilers > alignof - part of the compiler > > But, I forgot this one: > offsetof() - part of C (macro in stddef.h) > > offsetof() gets the offsets of something, like the element of a struct > or union. Look at the macro in stddef.h or Google "offsetof macro". Thanks, I didn't know about offsetof. ... > If you have a preprocessor, you can use it. If not, I think you'll > have to insert an expanded definition everywhere you need it ..., > or perhaps implement it within the compiler. The compiler should > have the necessary information to do it since it knows the struct > or union layout and sizes of everything in it's symbol tables etc. Let's take a step back as I didn't clearly explain the point I was making about headers. I was thinking that they normally contain the interface information for a source file. For a source file called source.c the header will normally be called source.h and it will define all of the info that another source file needs in order to interface with functions in source.c. So any program that wants to call services in source.c will #include source.h first. That will tell the compiler the interface info it needs to know. What might header source.h contain? Here are two possible types of information: 1. Integer constants. For example, EOF in stdio.h. 2. Structs. For example, struct timespec in time.h. Header files are a poor mechanism because there is no guarantee that the header used when the caller is compiled is the same header that was used when the callee is compiled. But with some discipline they can be effective. I was trying to say that things like struct timespec would need to be communicated to a program that interfaces with time functions. If the caller wants to update field tv_nsec of a struct timespec it needs to know its offset and its type at compile time. Without the header mechanism how could that info be made available to the calling module? >> Could #if and friends be omitted, for example by including >> executable tests in the code? > > #if #endif #ifdef could be replaced by regular if statements, > with a flag or variable to indicate which code is active. Good. > #define's in the code can be replaced with the value or expanded > macro, etc. What about the EOF example, above? How would a caller which needed to know the value of EOF used by the standard IO functions know what value EOF had been set to? > I don't think there is an easy way to handle #include, except > cut-n-paste the entire include ... Not sure. Maybe the individual parts which are #included could be communicated in some other - better - way. James
[toc] | [prev] | [next] | [standalone]
| From | "Rod Pemberton" <dont_use_email@xnothavet.cqm> |
|---|---|
| Date | 2014-05-07 19:04 -0400 |
| Message-ID | <op.xfiic4pj6zenlw@localhost> |
| In reply to | #2209 |
On Wed, 07 May 2014 06:55:57 -0400, James Harris <james.harris.1@gmail.com> wrote: > "Rod Pemberton" <dont_use_email@xnothavet.cqm> wrote in message > news:op.xfesqctt6zenlw@localhost... >> If you have a preprocessor, you can use it. If not, I think you'll >> have to insert an expanded definition everywhere you need it ..., >> or perhaps implement it within the compiler. The compiler should >> have the necessary information to do it since it knows the struct >> or union layout and sizes of everything in it's symbol tables etc. > > Let's take a step back as I didn't clearly explain the point I was making > about headers. I was thinking that they normally contain the interface > information for a source file. For a source file called source.c the > header will normally be called source.h and it will define all of the > info that another source file needs in order to interface with functions > in source.c. > > So any program that wants to call services in source.c will #include > source.h first. That will tell the compiler the interface info it needs > to know. That's one way to do it. That's commonly done for C, but not required. Personally, I prefer all-in-one programs if they're small. > What might header source.h contain? Here are two possible types of > information: > > 1. Integer constants. For example, EOF in stdio.h. > 2. Structs. For example, struct timespec in time.h. > function prototypes, structs, unions, enums, #defines, macros, ... > Header files are a poor mechanism because there is no guarantee that the > header used when the caller is compiled is the same header that was used > when the callee is compiled. But with some discipline they can be > effective. Should a distinction be maded between a program which includes it's own header file and a program which includes a C library header file? In one case, the source which uses those headers are compiled too, but not for the other. The other is compiled as a library. > I was trying to say that things like struct timespec would need to be > communicated to a program that interfaces with time functions. So, you're planning to object-orient-ize that struct somehow? ;-) > If the caller wants to update field tv_nsec of a struct timespec it > needs to know its offset and its type at compile time. Yes. > Without the header mechanism how could that info be made available > to the calling module? Didn't we have some conversation on something like this at least once before, i.e., in reference to passing structs and data over a network? It could query what fields the function expects, but I don't quickly recognize how the code would decide what to put into the fields. I.e., some intelligence is involved here, which can be captured by the code, but it's better if each side understands what to expect. E.g., if the calling module expects to pass a struct of a certain format, an integer, and a string, but the queried function says the struct has more members, the string is the wrong size, etc how does the callee fix that? > What about the EOF example, above? How would a caller which needed > to know the value of EOF used by the standard IO functions know > what value EOF had been set to? That one is more concrete. If the code was designed to support different EOF values, then code could query the value the other side is using and use that. If the code is compiled for a value which is different, then the code isn't going to be compatible. > [better way] What's with the need for all the abstraction? Are you still working on object-oriented stuff? Rod Pemberton
[toc] | [prev] | [next] | [standalone]
| From | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| Date | 2014-05-08 10:14 +0100 |
| Message-ID | <lkfht2$k2p$1@dont-email.me> |
| In reply to | #2217 |
"Rod Pemberton" <dont_use_email@xnothavet.cqm> wrote in message news:op.xfiic4pj6zenlw@localhost... ... >> What might header source.h contain? Here are two possible types of >> information: >> >> 1. Integer constants. For example, EOF in stdio.h. >> 2. Structs. For example, struct timespec in time.h. >> > > function prototypes, structs, unions, enums, #defines, macros, ... Function prototypes are an especially good example. >> Header files are a poor mechanism because there is no guarantee that the >> header used when the caller is compiled is the same header that was used >> when the callee is compiled. But with some discipline they can be >> effective. > > Should a distinction be maded between a program which includes it's own > header file and a program which includes a C library header file? > > In one case, the source which uses those headers are compiled too, but > not for the other. The other is compiled as a library. Sorry, I didn't understand that point. >> I was trying to say that things like struct timespec would need to be >> communicated to a program that interfaces with time functions. > > So, you're planning to object-orient-ize that struct somehow? ;-) I see the smiley so know you are kidding but I cannot see the connection. I wasn't thinking of any object orientation issues here. If your comment is about me saying "communicated to a program that interfaces with" I was thinking only about info comminicated at compile time - nothing dynamic. >> If the caller wants to update field tv_nsec of a struct timespec it >> needs to know its offset and its type at compile time. > > Yes. > >> Without the header mechanism how could that info be made available >> to the calling module? > > Didn't we have some conversation on something like this at least once > before, i.e., in reference to passing structs and data over a network? If we did that sounds like a dynamic issue. The info in the header such as a struct layout is about compile time so is very static! As an example of a header communicating a structure layout consider compiling the following reference to a structure struct timespec *tp; tp->tv_nsec = 0; That might compile to mov [esi + 4], dword 0 The point is that to produce this code the offset (4 in this case) of the field from the pointer needs to be known at compile time. The header would supply the struct definition from which the compiler works out the offset. I suppose the offset (4) might be filled in a link or load time. Interesting! > It could query what fields the function expects, but I don't quickly > recognize how the code would decide what to put into the fields. > > I.e., some intelligence is involved here, which can be captured by the > code, but it's better if each side understands what to expect. E.g., > if the calling module expects to pass a struct of a certain format, an > integer, and a string, but the queried function says the struct has > more members, the string is the wrong size, etc how does the callee > fix that? Yes, C's header mechanism normally supplies the interface info so that they match... as long as the right header is used, that is! >> What about the EOF example, above? How would a caller which needed >> to know the value of EOF used by the standard IO functions know >> what value EOF had been set to? > > That one is more concrete. If the code was designed to support > different EOF values, then code could query the value the other side > is using and use that. If the code is compiled for a value > which is different, then the code isn't going to be compatible. I think this too is normally done at compile time so that, for example, if (retval == EOF) might compile to cmp eax, -1 where, in this case, I have used -1 for EOF. The specific value would have come from a header, probably stdio.h. > What's with the need for all the abstraction? Hard to answer that as I'm not sure that there is a lot of abstraction here (in the C header mechanism, that is). > Are you still working on object-oriented stuff? Umm, not in connection with this but, depending on what you mean, possibly. Might make an interesting topic for a separate thread...? James
[toc] | [prev] | [next] | [standalone]
| From | "Rod Pemberton" <dont_use_email@xnothavet.cqm> |
|---|---|
| Date | 2014-05-08 07:35 -0400 |
| Message-ID | <op.xfjg4u1y6zenlw@localhost> |
| In reply to | #2221 |
On Thu, 08 May 2014 05:14:10 -0400, James Harris <james.harris.1@gmail.com> wrote: > "Rod Pemberton" <dont_use_email@xnothavet.cqm> wrote in message > news:op.xfiic4pj6zenlw@localhost... >> James wrote: [added some context back in] >>> Let's take a step back as I didn't clearly explain the point I was >>> making about headers. I was thinking that they normally contain the >>> interface information for a source file. For a source file called >>> source.c the header will normally be called source.h and it will >>> define all of the info that another source file needs in order to >>> interface with functions in source.c. So any program that wants >>> to call services in source.c will #include source.h first. That >>> will tell the compiler the interface info it needs to know. >>> >>> [...] >>> >>> Header files are a poor mechanism because there is no guarantee that >>> the header used when the caller is compiled is the same header that >>> was used when the callee is compiled. But with some discipline they >>> can be effective. >> >> Should a distinction be maded between a program which includes it's >> own header file and a program which includes a C library header file? >> >> In one case, the source which uses those headers are compiled too, >> but not for the other. The other is compiled as a library. > > Sorry, I didn't understand that point. > A header can be used with both the caller and callee to define the interface and provide the interface information, yes? The interface was defined by/for the callee. The code which implements the interfaces is only within the callee. The header is available to both, so that both may call that code. But, there are other situations where headers are used. One is where a program uses it's own header, but nothing else does. If a program defines an interface, that interface isn't shared. So, the header is really exclusive to that code. Should a distinction be made as to how header files are used? >>> I was trying to say that things like struct timespec would need to >>> be communicated to a program that interfaces with time functions. >> >> So, you're planning to object-orient-ize that struct somehow? ;-) > > I see the smiley so know you are kidding but I cannot see the > connection. I wasn't thinking of any object orientation issues here. Ok. That's what I was "asking". I presumed this could be for an object-oriented situation, or possibly similar in nature. I was being humorous in my response but, I perceived converting such a struct to an object-oriented use might be a bit more complicated. >>> Without the header mechanism how could that info be made available >>> to the calling module? >> >> Didn't we have some conversation on something like this at least once >> before, i.e., in reference to passing structs and data over a network? > > If we did that sounds like a dynamic issue. The info in the header such > as a > struct layout is about compile time so is very static! Yes, but it goes to the same or similar nature of the code on one side not "knowing" what the code on the other side provides and not "knowing" how to call the interace and not "knowing" what parameters are required. I.e., I keep getting the impression you're attempting to interface with a "black box". > As an example of a header communicating a structure layout consider > compiling the following reference to a structure > > struct timespec *tp; > tp->tv_nsec = 0; > > That might compile to > > mov [esi + 4], dword 0 > > The point is that to produce this code the offset (4 in this case) > of the field from the pointer needs to be known at compile time. > The header would supply the struct definition from which the compiler > works out the offset. > > I suppose the offset (4) might be filled in a link or load time. > Interesting! > At some point, you need the offset of tv_nsec and the address of the timespec struct, or you need the direct address of tv_nsec. With indirect addressing, you could do something like: ; address timespec + offset tv_nsec mov esi, [address_of_tv_nsec_address] mov eax, [address_of_tv_nsec_offset] lea eax, [esi + eax] mov [eax], dword 0 Or, ; address timespec + offset tv_nsec mov esi, [address_of_tv_nsec_address] mov eax, [address_of_tv_nsec_offset] mov [esi + eax], dword 0 Or, ; address tv_nsec mov eax, [address_of_tv_nsec] mov [eax], dword 0 Here, 'address_of...' are fixed locations in a list or table of all the other needed addresses and offsets. The table/list of needed addresses or offsets are filled in either at compile time or run-time. Rod Pemberton
[toc] | [prev] | [next] | [standalone]
| From | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| Date | 2014-05-08 16:22 +0100 |
| Message-ID | <lkg7fg$aek$1@dont-email.me> |
| In reply to | #2224 |
"Rod Pemberton" <dont_use_email@xnothavet.cqm> wrote in message news:op.xfjg4u1y6zenlw@localhost... > On Thu, 08 May 2014 05:14:10 -0400, James Harris > <james.harris.1@gmail.com> wrote: >> "Rod Pemberton" <dont_use_email@xnothavet.cqm> wrote in message >> news:op.xfiic4pj6zenlw@localhost... >>> James wrote: > > [added some context back in] > >>>> Let's take a step back as I didn't clearly explain the point I was >>>> making about headers. I was thinking that they normally contain the >>>> interface information for a source file. For a source file called >>>> source.c the header will normally be called source.h and it will >>>> define all of the info that another source file needs in order to >>>> interface with functions in source.c. So any program that wants >>>> to call services in source.c will #include source.h first. That >>>> will tell the compiler the interface info it needs to know. >>>> >>>> [...] >>>> >>>> Header files are a poor mechanism because there is no guarantee that >>>> the header used when the caller is compiled is the same header that >>>> was used when the callee is compiled. But with some discipline they >>>> can be effective. >>> >>> Should a distinction be maded between a program which includes it's >>> own header file and a program which includes a C library header file? >>> >>> In one case, the source which uses those headers are compiled too, >>> but not for the other. The other is compiled as a library. >> >> Sorry, I didn't understand that point. >> > > A header can be used with both the caller and callee to define the > interface and provide the interface information, yes? The interface > was defined by/for the callee. The code which implements the interfaces > is only within the callee. The header is available to both, so that both > may call that code. But, there are other situations where headers are > used. One is where a program uses it's own header, but nothing else does. > If a program defines an interface, that interface isn't shared. So, the > header is really exclusive to that code. Should a distinction be made > as to how header files are used? I can say how I use them. To set a context I should say that #include can bring in any source code but is usually used to bring in header files and that the content of an included header file could, instead, appear in the source instead of the #include statement. So,... what I tend to do is where I want something to be private to a source file I write it in the source file, and where I want something to be available to other modules I put it in a header. To make an example, say a single source file, source.c, has two functions, funcPublic and funcPrivate and that they appear in that order in the source file and that funcPublic calls funcPrivate. The files would look as follows. source.h int funcPublic(int); /* Declare the public function */ source.c #include "source.h" int funcPrivate(int); /* Declare the private function */ Doing it this way means that source.c sees both declarations but another module which includes source.h will only see the funcPublic declaration. Both of the functions would appear later in source.c but because only funcPublic appears in a header file it is the only function that other source code modules can learn about. Yet within source.c funcPublic and funcPrivate will be able to call each other as required. ... >>>> Without the header mechanism how could that info be made available >>>> to the calling module? >>> >>> Didn't we have some conversation on something like this at least once >>> before, i.e., in reference to passing structs and data over a network? >> >> If we did that sounds like a dynamic issue. The info in the header such >> as a >> struct layout is about compile time so is very static! > > Yes, but it goes to the same or similar nature of the code on one side > not "knowing" what the code on the other side provides and not "knowing" > how to call the interace and not "knowing" what parameters are required. > > I.e., I keep getting the impression you're attempting to interface with > a "black box". OK. Am guessing as to why you might get that impression but possibly it is because I try to modularise quite a lot. I remember a comment you made earlier about keeping things in one module if they are small enough. I do that too sometimes but more often try to split things up for a number of reasons, e.g. I find it makes them easier to reuse in other projects. Have you come across these principles? http://web.engr.oregonstate.edu/~budd/Books/oopintro3e/info/slides/chap03/slide28.htm The approach is a form of data hiding and an excellent approach, IMO. The effort to reduce 'public' information may be why to you I seem to be interfacing with a black box. As part of the topic we are discussing, though, I would put public interface information into a C header file. >> As an example of a header communicating a structure layout consider >> compiling the following reference to a structure >> >> struct timespec *tp; >> tp->tv_nsec = 0; >> >> That might compile to >> >> mov [esi + 4], dword 0 >> >> The point is that to produce this code the offset (4 in this case) >> of the field from the pointer needs to be known at compile time. >> The header would supply the struct definition from which the compiler >> works out the offset. >> >> I suppose the offset (4) might be filled in a link or load time. >> Interesting! >> > > At some point, you need the offset of tv_nsec and the address of > the timespec struct, or you need the direct address of tv_nsec. > With indirect addressing, you could do something like: > > ; address timespec + offset tv_nsec > > mov esi, [address_of_tv_nsec_address] > mov eax, [address_of_tv_nsec_offset] > lea eax, [esi + eax] > mov [eax], dword 0 > > Or, > ; address timespec + offset tv_nsec > > mov esi, [address_of_tv_nsec_address] > mov eax, [address_of_tv_nsec_offset] > mov [esi + eax], dword 0 > > Or, > ; address tv_nsec > mov eax, [address_of_tv_nsec] > mov [eax], dword 0 > > Here, 'address_of...' are fixed locations in a list or table of all > the other needed addresses and offsets. The table/list of needed > addresses or offsets are filled in either at compile time or run-time. Yes, I can see the principle. That should work. James
[toc] | [prev] | [next] | [standalone]
| From | "Rod Pemberton" <dont_use_email@xnothavet.cqm> |
|---|---|
| Date | 2014-05-09 16:45 -0400 |
| Message-ID | <op.xfl1afv66zenlw@localhost> |
| In reply to | #2226 |
On Thu, 08 May 2014 11:22:31 -0400, James Harris <james.harris.1@gmail.com> wrote: > "Rod Pemberton" <dont_use_email@xnothavet.cqm> wrote in message > news:op.xfjg4u1y6zenlw@localhost... >> I.e., I keep getting the impression you're attempting to interface with >> a "black box". > > OK. Am guessing as to why you might get that impression but possibly it > is because I try to modularise quite a lot. Ok. Yeah, that could be it. It just seems to me sometimes that it's like you're creating something which has no information about what it is connecting with, none, zero. ;-) > Have you come across these principles? > > [Parnas "rules"] > I'm going to say: "No." Of course, one could say the phrase "should provide no other information" of each clause is rather vague, unclear, and/or arbitrary, etc. What exactly is the meaning of "no other information" in that context? Does the "no other information" refer to, A) for the 1st clause: 1) exclusively information completely unrelated to the "services provided" or external to it? 2) #1 and the information for services not necessarily needed for "effective use" but still provided for use? 3) any information related to the "services provided" which are internal to those services which may be exposed to the user? etc. B) for the 2nd clause: 1) information completely unrelated to the "responsibilities assigned"? 2) information for responsibilities not assigned but may eventually be assigned? etc. I would have argue that limiting some information, which Parnas thinks clearly thinks is irrelevant or extraneous, would cause design or implementation problems in the future. The phrases "too limiting" and "too unknown" comes to mind. E.g., I would expect to have *all* information needed to use the services even if some of that information is *not* needed for "effective use". It may still be required for uses which are arbitrarily deemed ineffective use by others. E.g., if your manager says that there is the possibility the code will be extended in a certain way in the future, you're going to allow for that in your current design even though it's *not* an assigned responsibility. If you don't, you could have serious problems fixing things in the future. Rules always have a reason for their existence, but the rules never tell you _why_ the rule was created in the first place. The rules never tell you their purpose. So, you always have determine why the rule exists, what are the original constraints under which the rule was created, and then you have to ask if the rule is still valid or ever made any sense at all. So, you may want ask yourself what is the real purpose behind the Parnas rules: 1) is it to prevent code bloat? 2) is it to prevent feature creep? 3) is it to prevent miscommunication? 4) is it to prevent coding mistakes? 5) is it to prevent conflicts between user and developer? 6) is it to control proprietary information? 7) is it to keep a project on target, on budget? etc. A "slide" or two back: "The user of a software component need only know what it does, not how it does it." I would agree and disagree with that. Who is the user? It doesn't define who the "user" is. Without defining that, the statement may be invalid. I.e., does user mean *all* users with *no* exceptions? If the "user" is an end-user of an application, then they can be kept in the dark. They only need to understand the application's interface, and don't need to understand anything to do with the modules involved. Information hiding works just fine for them. If the "user" is another computer programmer, then they *absolutely* need to know what the "software component" does to make a decision as to whether the component is capable of "effective use" or not. A programmer needs to understand the modules interface and how the module works. If the programmer goes ahead and uses the "black box" without understanding what it does because he/she has no access to it, that could create some future complications. It may be doing too much, not enough, be too slow, or be doing something it's not supposed to do. It seems this is about object-oriented languages, and it mentions "information hiding". As a programmer, information hiding is a *bad* thing. That's when an internal function has been hidden or not exposed, or when access to it has been denied. It's always in those situations that you find you need access to that component. You know what you need is in there, but you can't use it, e.g., intermediate operation in a C library function, or a sub-function used by the OS, etc. IMO, one of the reasons that C is viewed as a "rich" language for programming is because almost everything the language does is available to the programmer for their use, i.e., very little is hidden or restricted. > The approach is a form of data hiding and an excellent approach, IMO. > > The effort to reduce 'public' information may be why to you I seem to be > interfacing with a black box. As part of the topic we are discussing, > though, I would put public interface information into a C header file. ... Rod Pemberton
[toc] | [prev] | [next] | [standalone]
| From | "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> |
|---|---|
| Date | 2014-05-10 09:04 +0200 |
| Message-ID | <1jy1ogca55286$.hxrf634zi430$.dlg@40tude.net> |
| In reply to | #2229 |
On Fri, 09 May 2014 16:45:41 -0400, Rod Pemberton wrote: > On Thu, 08 May 2014 11:22:31 -0400, James Harris > <james.harris.1@gmail.com> wrote: >> Have you come across these principles? >> >> [Parnas "rules"] > > I'm going to say: "No." > > Of course, one could say the phrase "should provide no other information" > of each clause is rather vague, unclear, and/or arbitrary, etc. > > What exactly is the meaning of "no other information" in that context? > Does the "no other information" refer to, You missed another important software design principle: a program must be designed in a way that separates information needed for use (interface) and arbitrary, thus volatile information (implementation). If you disregard this, then Parnas' principles make no sense. > It seems this is about object-oriented languages, and it mentions > "information hiding". As a programmer, information hiding is a > *bad* thing. No, it is a method of maintaining complexity and so of making collective software production possible (roles, separate design, testing, maintenance). It is not bad or good, it is the only way software engineering may function. Yes, proper engineering processes and techniques on small scale are considered unnecessary overhead, boring, and they certainly are. The problem is that programmes can only be taught on small things first. This is why C is so popular, and also so damaging to software developing in general. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
[toc] | [prev] | [next] | [standalone]
Page 1 of 4 [1] 2 3 4 Next page →
Back to top | Article view | comp.lang.misc
csiph-web