September 25, 2002 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sandor Hojtsy | Sandor Hojtsy wrote: > "Burton Radons" <loth@users.sourceforge.net> wrote in message > news:amo25r$1ga$1@digitaldaemon.com... > >>Walter wrote: >> >>>"Sandor Hojtsy" <hojtsy@index.hu> wrote in message >>>news:ammnbk$1gvd$1@digitaldaemon.com... >>> >>>>In general: we should consider all the aspects the C #define was used > > for, > >>>>and try to provide an alternative for the yet unadressed ones. >>> >>>You can always do some things with a text processor that can't be done >>>reasonably with a symbolic processor, but I think D comes pretty close > > to > >>>having a superior solution for at least the common things done with >>>#define's. I find the C preprocessor inadequate many times, and have > > turned > >>>to specialized C programs that generate C source for table building. You > > can > >>>see an example in idgen.c in the D front end source. >> >>No, no, Sandor wasn't advocating metaprogramming or preprocessing, just >>a high level of introspection. > > > Exactly, in this particular case. I think it would be a more ellegant > solution. > > And Walter: > Beware! Your (named indexes) solution now include three lists! One list of > the enum value names, when defining the enum type, and the two other lists > (merged) when initializing the array. Only the possibility of the "order > error" was removed, with yet more redundancy. But what about the "missing > element error"? > > >>This level of introspection is in my >>port (I think it's the find method on the EnumInfo, wrong OS to check). > > > Wow! > > >> But it's had questionable value, as most enums are of the form: >> >> typedef int GLenum; >> enum : GLenum >> { >> GL_FALSE = (GLenum) 0, >> .... >> } >>So you can't name it. > > Interesting. That is a workaround for a feature which was considered a Good > Think (scoped enum names). > Why do we need workaround here? Because the language doesn't have native > support for non-scoped enum names, and they are still required! > If it had, you would have no problem naming the enum type. I can't think of a syntax. Scoped enums look like a good thing, but the problem is that lots of the time the enumeration is a language keyword, requiring either "In", "_in", or "IN", none of which look very nice in use. Perhaps: enum typedef GLenum : int { GL_FALSE = 0, .... } Insane, but it works. It doesn't speak "nonscoped enum", but then again, "for" doesn't speak "looping construct"; we only think of it that way because that's what we've learned to associate with it. Oh, right, introspection. I doubt Walter would go for getting the name of an enumeration unless if it has demonstrable necessary value, as it's by far the most memory-intensive part of introspection and hasn't been used in any code of mine yet - and unlike safe varargs, I don't think it's because it's not really useable. Preprocessing could be part of a standard package-building and distribution system. I could have a file like: char [] [] names; int [] values; input syntax line (name is string) (value is integer) { if (type != "line") return; names ~= name; values ~= value; } body { GL_FALSE 0 GL_TRUE 1 ... } output GLenum { println ("typedef int GLenum;"); println ("enum : GLenum\n{"); for (int c; c < names.length; c ++) println (" %s = %d,", names [c], values [c]); println ("}"); } output GLenumToString { char [] [int] match; for (int c = names.length - 1; c >= 0; c --) match [values [c]] = names [c]; println ("char [] GLenumToString (GLenum value)\n{"); println (" switch (value)\n{"); int [] keys = match.keys; for (int c; c <= keys.length; c ++) println (" case 0x%x: return \"%s\";", keys [c], match [keys [c]]); println (" default: return null;"); println (" }\n}"); } Then in the appropriate source: /++ glenums GLenum ++/ /++ glenums GLenumToString ++/ It would then build a preprocessor, run it, and insert the result. One big advantage here is that it doesn't make a mess of debugging; if I were making complex functions, I could trace them. >> Oh, and note the cast. Let's make it so that if >>you're defining an enum, an explicit cast is implied. > > I don't understand. My example was "GL_FALSE = (GLenum) 0,"; I can't write that "GL_FALSE = 0,", because that would be an implicit cast to a typedef. For the definition only, this explicit cast should be implied, as there's about a thousand GL enumerations. |
September 25, 2002 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mark Evans | "Mark Evans" <Mark_member@pathlink.com> wrote in message news:amqpnk$t0j$1@digitaldaemon.com... > I do not want to define the same things in 3 places! The preprocessor meta-macros in the preceeding are ugly as sin, but have the virtue of localizing > all definitions in one place. There's a more general problem there about synchronizing multiple tables, enums, symbols, and values. At its most complex, you've got YACC and LEX. D goes a big step forward by supporting named initializers, but it is never going to support things like token concatenation (because that would prevent the separation of lexing and parsing). Best I can suggest is do to things like \dmd\src\d\idgen.c, where one program generates the source for another. |
September 25, 2002 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Burton Radons | "Burton Radons" <loth@users.sourceforge.net> wrote in message news:amr5ab$19t2$1@digitaldaemon.com... > >> But it's had questionable value, as most enums are of the form: > >> > >> typedef int GLenum; > >> enum : GLenum > >> { > >> GL_FALSE = (GLenum) 0, > >> .... > >> } > >>So you can't name it. > > > > Interesting. That is a workaround for a feature which was considered a Good > > Think (scoped enum names). > > Why do we need workaround here? Because the language doesn't have native > > support for non-scoped enum names, and they are still required! > > If it had, you would have no problem naming the enum type. > > I can't think of a syntax. You can't think of a (new) syntax for defining an unscoped enum? unscoped enum GLenum { GL_FALSE = 0; ... } > Scoped enums look like a good thing, but the > problem is that lots of the time the enumeration is a language keyword, For example? > requiring either "In", "_in", or "IN", none of which look very nice in use. > > Perhaps: > > enum typedef GLenum : int > { > GL_FALSE = 0, > .... > } > > Insane, but it works. It doesn't speak "nonscoped enum", but then again, "for" doesn't speak "looping construct"; we only think of it that way because that's what we've learned to associate with it. for speaks "for all" I still can't see how your syntax works. What is the name of the enum type? How many types are you defining here? > Oh, right, introspection. I doubt Walter would go for getting the name of an enumeration unless if it has demonstrable necessary value, as it's by far the most memory-intensive part of introspection I don't mean that all executables should include enum name introspection tables for all enums! Only for the enums the code is actually using in instrospection. I don't see the size difference between automatically including the enum names where necessary, or manually writing them into the source code as string literals. In the end, they should eat the same memory. The executable will be of the same size. Only source code will be shorter and cleaner. > and hasn't been used in any code of mine yet - and unlike safe varargs, I don't think > it's because it's not really useable. Preprocessing could be part of a standard package-building and distribution system. I think a medium sized project, with an apropriate language should be OK without preprocessing. > I could have a file like: Is this a D source code? It uses some features unknown to me. > char [] [] names; > int [] values; > > input > syntax line (name is string) (value is integer) > { > if (type != "line") > return; > names ~= name; > values ~= value; > } > body > { > GL_FALSE 0 > GL_TRUE 1 > ... > } > > output GLenum > { > println ("typedef int GLenum;"); > println ("enum : GLenum\n{"); > for (int c; c < names.length; c ++) > println (" %s = %d,", names [c], values [c]); > println ("}"); > } > > output GLenumToString > { > char [] [int] match; > > for (int c = names.length - 1; c >= 0; c --) > match [values [c]] = names [c]; > > println ("char [] GLenumToString (GLenum value)\n{"); > println (" switch (value)\n{"); > > int [] keys = match.keys; > > for (int c; c <= keys.length; c ++) > println (" case 0x%x: return \"%s\";", keys [c], > match [keys [c]]); > > println (" default: return null;"); > println (" }\n}"); > } > > Then in the appropriate source: > > /++ glenums GLenum ++/ > /++ glenums GLenumToString ++/ > > It would then build a preprocessor, run it, and insert the result. It? You mean a makefile will build a preprocessor (by invoking the D compiler on what?), the makefile will run the preprocessor, and the preprocessor will insert the result to an other source file, modifying it? > One > big advantage here is that it doesn't make a mess of debugging; if I > were making complex functions, I could trace them. IMHO source code generation makes debugging slow. You find the error in the pretty generated source, then lookup the generator by hand, try to find the error in that file. You should correct it inside strings (no syntax color), where all kinds of escaping is needed such as backslash-backslash-n, backslash-quote, %%, and such kinds of ugly hard-to-read constructs. Actually a code generator will be so ugly you will start to think about generating the generator itself, with some other tool. > >> Oh, and note the cast. Let's make it so that if > >>you're defining an enum, an explicit cast is implied. > > > > I don't understand. > > My example was "GL_FALSE = (GLenum) 0,"; I can't write that "GL_FALSE = 0,", because that would be an implicit cast to a typedef. For the definition only, this explicit cast should be implied, as there's about a thousand GL enumerations. Yes. But that problem will also be solved by native unscoped enums, won't it? |
September 25, 2002 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sandor Hojtsy | One of the things that makes Python so powerful is runtime introspection. It's truly awesome. I would always vote in favor of that feature in any language. I agree with Sandor's point about escape sequences. They are ugly and error-prone. As usual I don't have an answer, just lots of opinions! Mark |
September 25, 2002 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mark Evans | Mark Evans <Mark_member@pathlink.com> wrote in news:amt5d2$jgm$1@digitaldaemon.com: > One of the things that makes Python so powerful is runtime introspection. It's truly awesome. I would always vote in favor of that feature in any language. Yes it is truly awesome. > > I agree with Sandor's point about escape sequences. They are ugly and error-prone. It is ugly but often worth it. I think I've litterly saved myself weeks of time just by writing a little code generator for various stuff. |
September 26, 2002 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Patrick Down |
>>
>> I agree with Sandor's point about escape sequences. They are ugly and error-prone.
>
>It is ugly but often worth it. I think I've litterly saved myself weeks of time just by writing a little code generator for various stuff.
>
But typically one uses a different language, e.g. Perl/Python/Icon, to auto-gen code in a target language like C, C++, or D.
In the time taken to write / test / modify / finalize a code gen tool, I can design preprocessor stuff that will simply compile directly. I have done few projects for which code gen offered a reasonable return on investment. Changes are inevitable, and it's often simpler to make them by hand, than modify a code gen program with all its ugly escape sequences and testing issues.
The evolution trend of compilers is toward an incorporation of code generation, such as vtables, templates, and now with .NET, runtime compilation (as I understand .NET). So to ask D for such features is not entirely out of line.
Mark
|
October 02, 2002 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mark Evans | "Mark Evans" <Mark_member@pathlink.com> wrote in message news:amtl9n$152h$1@digitaldaemon.com... > But typically one uses a different language, e.g. Perl/Python/Icon, to auto-gen > code in a target language like C, C++, or D. Not me - check out \dmd\src\dmd\idgen.c (!) Using some other language is convenient at the time, but usually turns into a significant nuisance 3 years later when you need to build a new version from the source, and can't find a copy of Perl version X.Y.Z or Perl X.Y.Z won't run on the machine you're porting your code to, etc. (That's why I abandoned using Bison.) > In the time taken to write / test / modify / finalize a code gen tool, I can > design preprocessor stuff that will simply compile directly. I have done few > projects for which code gen offered a reasonable return on investment. Changes > are inevitable, and it's often simpler to make them by hand, than modify a code > gen program with all its ugly escape sequences and testing issues. > > The evolution trend of compilers is toward an incorporation of code generation, > such as vtables, templates, and now with .NET, runtime compilation (as I understand .NET). So to ask D for such features is not entirely out of line. I agree that the trend is towards ever more powerful constructs. |
October 02, 2002 Re: how to live without #define | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter |
>convenient at the time, but usually turns into a significant nuisance 3 years later when you need to build a new version from the source, and can't find a copy of Perl version X.Y.Z or Perl X.Y.Z
Well, your mistake is using an ugly cobbled-together excuse for a language like Perl instead of a real language like Python or Icon....Uh-oh, I just started a war.....
:-) Mark
|
Copyright © 1999-2021 by the D Language Foundation