D - Generics in D
- Craig Black (68/68) Jun 24 2002 Walter,
- Matthew Wilson (21/89) Jun 24 2002 I like your typelist idea, but am dubious about the compile-time switch....
- Burton Radons (34/63) Jun 24 2002 Good idea, but the new statements aren't necessary. Just having the
- cblack01 (53/117) Jun 24 2002 First,
- Burton Radons (75/120) Jun 27 2002 When you read later you'll understand what I mean when I say:
- Craig Black (17/137) Jun 27 2002 This is good stuff.
- Craig Black (7/7) Jun 27 2002 Burton,
- Craig Black (10/17) Jun 27 2002 I am going to answer my own question.
- Juan Carlos Arevalo Baeza (13/34) Jun 27 2002 Still, in order to make this work completely at compile time, the
- Burton Radons (9/15) Jun 27 2002 float[$b][$a] Inverse (float matrix[$a][$b]) { ... }
- Craig Black (13/14) Jun 28 2002 So in a generic function the $symbol can be a type, or an integer, or
- Sean L. Palmer (11/25) Jun 28 2002 We could use $ for types and # for values.
- cblack01 (6/11) Jun 28 2002 This would work if we assumed that all #symbol's were unsigned integers.
- Sean L. Palmer (11/24) Jun 29 2002 I was thinking that # would be "a value of any type". However I guess I...
- Pavel Minayev (7/8) Jun 29 2002 All these $ and # suddenly make it feel like Perl - which
- Patrick Down (23/35) Jun 29 2002 How about something like this.
- Pavel Minayev (33/33) Jun 30 2002 On Sat=2C 29 Jun 2002 22=3A25=3A55 +0000 =28UTC=29 Patrick Down =3Cpat=4...
- Sean L. Palmer (23/58) Jun 30 2002 Well this at least has a look that fits with the rest of D quite nicely.
- Sean L. Palmer (9/17) Jun 30 2002 If D source could use Unicode characters, we could use French quotation
- Burton Radons (61/61) Jun 29 2002 Craig Black wrote:
- Craig Black (13/50) Jul 01 2002 OK. Sounds like you know what you're talking about. Just to clarify in...
- Walter (6/8) Jul 03 2002 That's some of the problem with C++ templates. The rest of the complexit...
- Sean L. Palmer (10/18) Jul 05 2002 That could also suck alot of the ease-of-use out of them. Would mean
- Walter (13/18) Jul 05 2002 splicing
- Sean L. Palmer (46/64) Jul 05 2002 That will work. And it'll be simple and elegant.
- Walter (16/58) Jul 05 2002 Yes I know it'll be more typing. Perhaps I can find a way to reduce that
- Juan Carlos Arevalo Baeza (17/27) Jul 05 2002 maddening
- Walter (10/23) Jul 07 2002 the
- Sean L. Palmer (12/35) Jul 08 2002 I don't believe the scoping rules would work with that scheme, would it?
- Walter (5/8) Jul 08 2002 doesn't
- Sean L. Palmer (7/15) Jul 08 2002 Seems like it should only have access to:
- Walter (4/9) Jul 09 2002 To me either the symbols from the point of declaration or the point of
- Patrick Down (27/42) Jul 09 2002 Symbols from the point of declaration whould fit the function model best...
- Walter (3/45) Jul 09 2002 Hmm. I don't think that should work!
- Patrick Down (6/44) Jul 09 2002 Well even I will admit that the attaching a template
- Juan Carlos Arevalo Baeza (11/24) Jul 09 2002 template< class T >
- Sean L. Palmer (7/33) Jul 09 2002 And if T didn't have a name member, it would be an error to try to
- Sean L. Palmer (9/20) Jul 09 2002 Then I would pick the point of declaration; however you still need to b...
- Juan Carlos Arevalo Baeza (13/24) Jul 09 2002 So
- Sean L. Palmer (13/23) Jul 09 2002 Exactly. Move most of the actual code generation to *after* linking. S...
- Juan Carlos Arevalo Baeza (11/27) Jul 10 2002 the
- Juan Carlos Arevalo Baeza (30/40) Jul 08 2002 of
- Walter (6/9) Jul 09 2002 D's
- Sean L. Palmer (10/19) Jul 09 2002 sweet
- Walter (4/10) Jul 09 2002 Yeah, that will require some careful thought. -Walter
- Juan Carlos Arevalo Baeza (11/14) Jul 09 2002 are
- Sean L. Palmer (7/14) Jul 07 2002 Yeah, it seems difficult. I never implemented generics before. You're ...
- Nic Tiger (13/41) Jun 25 2002 Imagine that Add for numerical and Add for containers are placed in
- Patrick Down (45/58) Jun 25 2002 I generally like this form of generics. It works well for
- Craig Black (19/77) Jun 25 2002 Isn't this very similar to typedef or alias?
- Patrick Down (38/70) Jun 25 2002 Yes it is. But it's not all that weard C++ was forced to
- Patrick Down (2/5) Jun 25 2002 Sorry that was't very clear. I mean that C++ uses the template syntax
- Craig Black (8/34) Jun 25 2002 How about allowing compile-time conditionals outside of function context...
- Sean L. Palmer (4/41) Jun 26 2002 That's *very* close to the functionality of the current 'version' constr...
- C.R.Chafer (26/35) Jun 26 2002 Ignoring whether or not this is a good idea for the moment, I believe t...
- cblack01 (14/14) Jun 26 2002 Whichever is easiest to implement and give us the functionality we need.
- C.R.Chafer (18/27) Jun 26 2002 And we want something which is simple to type, easy to figure out the
-
OddesE
(17/34)
Jun 26 2002
"Patrick Down"
wrote in message - Pavel Minayev (3/10) Jun 26 2002 Well, I wouldn't say I know it very well, but I don't remember anything
- Alix Pexton (16/32) Jun 26 2002 Ada has a type type, if memory serves, so does ecmsScript 2.0 (not a pro...
- Patrick Down (9/20) Jun 26 2002 If you look in the D libary right now you will see that there is
- Pavel Minayev (6/13) Jun 27 2002 However, it's a run-time solution, as opposed to compile-time
- Patrick Down (41/57) Jun 27 2002 I agree. I think what I've suggested in earlier posts could
- Pavel Minayev (3/6) Jun 27 2002
- Craig Black (4/7) Jun 27 2002 I think the purpose of not using parens for templates in C++ was so that...
- Craig Black (12/19) Jun 27 2002 you
- Pavel Minayev (3/5) Jun 27 2002 It doesn't. You always have to use operator new to create an object. The...
- Juan Carlos Arevalo Baeza (12/14) Jun 27 2002 Actually, if the name references a template class, using the first se...
- Patrick Down (4/15) Jun 27 2002 Yes but they caused an equall number of problems in C++ with the >>
- Pavel Minayev (8/8) Jun 27 2002 On Thu=2C 27 Jun 2002 16=3A15=3A56 +0000 =28UTC=29 Patrick Down =3Cpat=4...
- Craig Black (29/29) Jul 02 2002 Hello,
- Walter (4/11) Jul 10 2002 TypeInfo certainly has promise for a more general type descriptor
- Sean L. Palmer (29/61) Jun 27 2002 void // only property is that it's a type, although you can't do *anyth...
- OddesE (76/76) Jun 27 2002 I suggested something similar to this in the
- anderson (5/5) Jun 25 2002 You'll have to wait a few days for Walters return.
- Walter (28/91) Jul 03 2002 going
Walter, First of all, I would like to say that I like the direction that D is going so far, and appreciate your innovative work on this new language. I know support for generics in D is probably still on the horizin, but have you given it any serious thought? We can definitely improve on C++ templates, both in ease of implementation and flexibility. Even before you start on templates it would be good to have in mind at least a vague concept of what you plan to do. I use C++ templates aggressively, so I have some ideas about features to add and drop. First, if you haven't read Modern C++ Design: Generic Programming and Design Patterns Applied by Andrei Alexandrescu, you should get a copy. A great book! I have already applied many of the concepts he covers. It should be required reading for anyone who wants in depth understand of Generic Programming. I have so many ideas and could write forever about generics, here's just some food for thought. If you're interested, I would be glad to share more ideas. I will just give you a few insights of where you can improve on C++. First, we generic programmers need a compile-time typeof operator. I have run into so many cases where I said to myself, "I sure wish I had a typeof operator." It would make generic programming so much more elegant. Then you could have compile-time conditionals to handle different types in different ways, like this: cswitch(typeof(variable)) { case int: // handle an integer case string: // hangle a string ... } Here "cswitch" is a compile-time conditional. This means the conditional is resolved at compile time, and optimized appropriately so that no performance is lost and dead code is eliminated. You could also have cif, celse, etc. Another idea I have to improve on C++ is type specialization syntax. We could implement type specialization more explicitly using typelists. This would provide a more readable type specialization that (I think) would be easier to implement. Here's a simple example: template <typename T : {int, uint, long, ulong, float, double}> T Add(T a, T b) { return a + b; } This specializes the Add function to need apply only to int, float, double, and extended. You could then write another Add template that would handle concatenation of container types. This leads me to another feature that would be nice to have: type lists (see chapter 3 of Modern C++ design.) It would be nice to categorize types something like this: typelist NumericTypes { int, uint, long, ulong, float, double }; typelist ContainerTypes { list, set, vector, queue, stack }; Then you could rewrite the Add function: template <typename T : NumericTypes> T Add(T a, T b) { return a + b; } template <typename T : ContainerTypes> T Add(T a, T b) { T result; result.append(a); result.append(b); return result; } Like I said, I have many other ideas, including making generic programming even more generic to reduce code duplication and improve maintainabiliity. Let me know what you think. Craig
Jun 24 2002
I like your typelist idea, but am dubious about the compile-time switch. Can you expound on this idea and give a non-trivial example? Matthew "Craig Black" <cblack ara.com> wrote in message news:af7k2g$1f31$1 digitaldaemon.com...Walter, First of all, I would like to say that I like the direction that D isgoingso far, and appreciate your innovative work on this new language. I know support for generics in D is probably still on the horizin, buthaveyou given it any serious thought? We can definitely improve on C++ templates, both in ease of implementation and flexibility. Even beforeyoustart on templates it would be good to have in mind at least a vagueconceptof what you plan to do. I use C++ templates aggressively, so I have some ideas about features to add and drop. First, if you haven't read Modern C++ Design: Generic Programming andDesignPatterns Applied by Andrei Alexandrescu, you should get a copy. A great book! I have already applied many of the concepts he covers. It shouldberequired reading for anyone who wants in depth understand of Generic Programming. I have so many ideas and could write forever about generics, here's just some food for thought. If you're interested, I would be glad to sharemoreideas. I will just give you a few insights of where you can improve on C++.First,we generic programmers need a compile-time typeof operator. I have runintoso many cases where I said to myself, "I sure wish I had a typeofoperator."It would make generic programming so much more elegant. Then you couldhavecompile-time conditionals to handle different types in different ways,likethis: cswitch(typeof(variable)) { case int: // handle an integer case string: // hangle a string ... } Here "cswitch" is a compile-time conditional. This means the conditionalisresolved at compile time, and optimized appropriately so that noperformanceis lost and dead code is eliminated. You could also have cif, celse, etc. Another idea I have to improve on C++ is type specialization syntax. We could implement type specialization more explicitly using typelists. This would provide a more readable type specialization that (I think) would be easier to implement. Here's a simple example: template <typename T : {int, uint, long, ulong, float, double}> T Add(T a, T b) { return a + b; } This specializes the Add function to need apply only to int, float,double,and extended. You could then write another Add template that would handle concatenation of container types. This leads me to another feature that would be nice to have: type lists(seechapter 3 of Modern C++ design.) It would be nice to categorize types something like this: typelist NumericTypes { int, uint, long, ulong, float, double }; typelist ContainerTypes { list, set, vector, queue, stack }; Then you could rewrite the Add function: template <typename T : NumericTypes> T Add(T a, T b) { return a + b; } template <typename T : ContainerTypes> T Add(T a, T b) { T result; result.append(a); result.append(b); return result; } Like I said, I have many other ideas, including making generic programming even more generic to reduce code duplication and improve maintainabiliity. Let me know what you think. Craig
Jun 24 2002
Craig Black wrote:I will just give you a few insights of where you can improve on C++. First, we generic programmers need a compile-time typeof operator. I have run into so many cases where I said to myself, "I sure wish I had a typeof operator." It would make generic programming so much more elegant. Then you could have compile-time conditionals to handle different types in different ways, like this: cswitch(typeof(variable)) { case int: // handle an integer case string: // hangle a string ... }Good idea, but the new statements aren't necessary. Just having the clauses in the language that: a) Dead code and blocks made inaccessible through constant folding must not be compiled. b) Trivial constant folding must be performed. Is enough to do the same. Then the above code becomes: switch(variable.typeinfo) { case int: case char[]: } These additions aren't difficult to comply with and have value elsewhere.Then you could rewrite the Add function: template <typename T : NumericTypes> T Add(T a, T b) { return a + b; } template <typename T : ContainerTypes> T Add(T a, T b) { T result; result.append(a); result.append(b); return result; }That could easily become, using my generics methodology: $T Add ($T a, $T b) { if ($T.has_field ("length")) return a ~ b; else return a + b; } So I think you introduced a good idea - cswitch/cif/celse - and then didn't use it right when it would work great. Can you produce an example of code where typelist is necessary? LX/XL has an interesting solution to the problem that automatically handles new types. The generic type for a min and max function is: generic type ordered if with ordered A, B with boolean Test := A < B So a type is ordered if it can handle (A < B) and return a boolean. Whether this is just a mind-blower or of actual value is hard to say at this point. Smalltalk has also been tossed around here on occasion, but I don't think anyone's described it and I can't google any information about it.
Jun 24 2002
"Burton Radons" <loth users.sourceforge.net> wrote in message news:3D17D5CE.3040608 users.sourceforge.net...Craig Black wrote:First,I will just give you a few insights of where you can improve on C++.intowe generic programmers need a compile-time typeof operator. I have runoperator."so many cases where I said to myself, "I sure wish I had a typeofhaveIt would make generic programming so much more elegant. Then you couldlikecompile-time conditionals to handle different types in different ways,Good points. It would just be nice to force the compiler to resolve the conditional at compile time, and give you an error message if it can't so that you know for sure whether the optimization is performed. Perhaps the compile-time conditionals are unnecessary, but if it a construct that is easily added to a language, it would ease my conscience to use them in performance-critical situations. Just a thought: the concept of compile-time conditionals could be extended to looping constructs (cfor, cwhile, etc) to force the unrolling of loops. This idea almost causes me to drool on myself.this: cswitch(typeof(variable)) { case int: // handle an integer case string: // hangle a string ... }Good idea, but the new statements aren't necessary. Just having the clauses in the language that: a) Dead code and blocks made inaccessible through constant folding must not be compiled. b) Trivial constant folding must be performed.Is enough to do the same. Then the above code becomes: switch(variable.typeinfo) { case int: case char[]: } These additions aren't difficult to comply with and have value elsewhere.I like this syntax. A quick question, as I am paranoid about performance, is the $T.has_field("length") resolved at compile time? I am assuming that "length" here is a static member variable. After all, we do not want to have to add a member variable every time we want to classify an attribute of a class. Another question, this looks to me like reflection, introspection, whatever you want to call it. In D, will this information be available at both run-time and compile-time? I can see applications for compile-time reflection and run-time reflection. Is there also an API to get a container of member methods, or a container member variables? An is_class() method? is_basic_type() method? If this API is in existence, and can be resolved at compile-time, then perhaps this is just the solution I have been looking for to solve all my generic programming problems.Then you could rewrite the Add function: template <typename T : NumericTypes> T Add(T a, T b) { return a + b; } template <typename T : ContainerTypes> T Add(T a, T b) { T result; result.append(a); result.append(b); return result; }That could easily become, using my generics methodology: $T Add ($T a, $T b) { if ($T.has_field ("length")) return a ~ b; else return a + b; }So I think you introduced a good idea - cswitch/cif/celse - and then didn't use it right when it would work great. Can you produce an example of code where typelist is necessary?All my examples (that I can think of right now) would be a result of the problems introduced with C++ generics. As mentioned previously, type lists would provide a more flexible and better solution for the ugly C++ specialization syntax, and C++ type traits. But as you have proposed above, perhaps compile-time reflection would be an even better solution.LX/XL has an interesting solution to the problem that automatically handles new types. The generic type for a min and max function is: generic type ordered if with ordered A, B with boolean Test := A < B So a type is ordered if it can handle (A < B) and return a boolean. Whether this is just a mind-blower or of actual value is hard to say at this point.I remember reading about LX one time. This guy is trying to unify every programming paradigm in existence into one language. An immense task. He certainly has some creative and original ideas. Unfortunately, even if he is successful, his language probably won't be widely adopted because the syntax is not close enough to C++, Java style syntax.Smalltalk has also been tossed around here on occasion, but I don't think anyone's described it and I can't google any information about it.Sorry, I don't know anything about Smalltalk, so I can't comment. Sounds to me like you are totally on the right track here. Perhaps compile-time reflection will more elegantly resolve many current issues in regard to generics. I guess my main concern is how well the compiler is able to resolve things at compile-time. This is what makes C++ templates so powerful. More concise, maintainable source code with absolutely no run-time overhead, because the compiler does all the work. Are you involved with the D compiler development? If you are, this gives me more confidence in D. Do you have specs for your implementation of generics? I think tommorrow I may post another idea and if you want you can critique it for me. Regards, Craig
Jun 24 2002
cblack01 wrote:Good points. It would just be nice to force the compiler to resolve the conditional at compile time, and give you an error message if it can't so that you know for sure whether the optimization is performed. Perhaps the compile-time conditionals are unnecessary, but if it a construct that is easily added to a language, it would ease my conscience to use them in performance-critical situations.When you read later you'll understand what I mean when I say: $type constant ($type $value) { return $value; } "if (constant (...))" is more cumbersome than "cif (...)", but cute nonetheless. Updated rules about mandatory trivial constant folding: a) Dead code and blocks made inaccessible through constant folding must not be compiled. b) Trivial constant folding must be performed. c) All methods and field accesses of ClassInfo, TypeInfo, and Interface that have constant parameters must be converted into the appropriate constant for further folding. d) If the compiler supports nontrivial constant folding, it must be aware of the distinction. If a block is made redundant due to nontrivial constant folding, but would be compiled with trivial constant folding, it must be compiled, even if it is subsequently thrown away. This is another effort to smooth the differences between compilers and disallow people from abusing their intelligent compiler.It's turned into one line of code at maximum at compile time. Should be using interfaces to indicate compliance instead, really.That could easily become, using my generics methodology: $T Add ($T a, $T b) { if ($T.has_field ("length")) return a ~ b; else return a + b; }I like this syntax. A quick question, as I am paranoid about performance, is the $T.has_field("length") resolved at compile time? I am assuming that "length" here is a static member variable. After all, we do not want to have to add a member variable every time we want to classify an attribute of a class.Another question, this looks to me like reflection, introspection, whatever you want to call it. In D, will this information be available at both run-time and compile-time? I can see applications for compile-time reflection and run-time reflection. Is there also an API to get a container of member methods, or a container member variables? An is_class() method? is_basic_type() method? If this API is in existence, and can be resolved at compile-time, then perhaps this is just the solution I have been looking for to solve all my generic programming problems.It will be in the future, at least for runtime. Nic's brought up the case of ... disjoint typelist genericism. Or something. My opinion is that once those issues kick into gear, not using methods to do this is criminal, particularly as using generic methods with super allows even more flexibility in doing this.Nope and nope. The generics stuff is just a shorthand at the moment - I haven't thought about how it would behave. But how about this. For generic functions and generic class methods, a "$" followed by an identifier in the place where a type would exist indicates a generic type. The specific type of this generic is determined by the first argument using it; a function cannot return a generic type only. For example: $type foo ($type a, $type b) $type bar (int c); /* Illegal */ complex x = foo (4, 2.3); /* Returns int and casts 2.3 to int */ Generic values are also prefixed with a $ and must be trivially constant. Generic values of type "TypeInfo" or "ClassInfo" are special in that they can be used both as a value and a generic type, and if so must be the first argument to use this generic value: $type cast (TypeInfo $type, $type value) { return value; } $type tsac ($type value, TypeInfo $type) /* Illegal */ cast (int, 4.3); /* Returns 4 */ A generic function that takes only generic types and values and only accesses other similarly compile-time values is considered trivially constant and must be folded. The generic function for a given function name and number of arguments is searched for eligibility after any specific-type functions. There can't be two generic functions with the same name and number of arguments as it's easy to make the overloading rules go crazy, and this restriction can be relaxed in the future. On to struct, class, and union. I've only taken the most obvious choice: struct Vector (TypeInfo $type, int $size) { $type [$size] array; } Vector (float, 4) x; struct Vector2 (TypeInfo $type) : Vector ($type, 2) { float x () { return array [0]; } float y () { return array [1]; } } struct Vector3 (TypeInfo $type) : Vector2 ($type) { float z () { return array [2]; } void z (float v) { array [2] = v; } } Vector3 (float) v; v.z = 16; Perhaps not Vector2 and Vector3, but the possibilities intrigue me. I _think_ the ambiguities that C++ was fighting against are nullified by D, which would be very good, as <> is not. I have also been thinking about making the generic values as a kind of virtual field and specifying their value in the constructor, but a usable syntax has not emerged. So in total it's just C++'s templates without the template keyword.Smalltalk has also been tossed around here on occasion, but I don't think anyone's described it and I can't google any information about it.Sorry, I don't know anything about Smalltalk, so I can't comment. Sounds to me like you are totally on the right track here. Perhaps compile-time reflection will more elegantly resolve many current issues in regard to generics. I guess my main concern is how well the compiler is able to resolve things at compile-time. This is what makes C++ templates so powerful. More concise, maintainable source code with absolutely no run-time overhead, because the compiler does all the work. Are you involved with the D compiler development? If you are, this gives me more confidence in D. Do you have specs for your implementation of generics?
Jun 27 2002
This is good stuff. --Craig "Burton Radons" <loth users.sourceforge.net> wrote in message news:3D1AD1CD.3080308 users.sourceforge.net...cblack01 wrote:soGood points. It would just be nice to force the compiler to resolve the conditional at compile time, and give you an error message if it can'tthethat you know for sure whether the optimization is performed. Perhapsperformance,compile-time conditionals are unnecessary, but if it a construct that is easily added to a language, it would ease my conscience to use them in performance-critical situations.When you read later you'll understand what I mean when I say: $type constant ($type $value) { return $value; } "if (constant (...))" is more cumbersome than "cif (...)", but cute nonetheless. Updated rules about mandatory trivial constant folding: a) Dead code and blocks made inaccessible through constant folding must not be compiled. b) Trivial constant folding must be performed. c) All methods and field accesses of ClassInfo, TypeInfo, and Interface that have constant parameters must be converted into the appropriate constant for further folding. d) If the compiler supports nontrivial constant folding, it must be aware of the distinction. If a block is made redundant due to nontrivial constant folding, but would be compiled with trivial constant folding, it must be compiled, even if it is subsequently thrown away. This is another effort to smooth the differences between compilers and disallow people from abusing their intelligent compiler.That could easily become, using my generics methodology: $T Add ($T a, $T b) { if ($T.has_field ("length")) return a ~ b; else return a + b; }I like this syntax. A quick question, as I am paranoid aboutthatis the $T.has_field("length") resolved at compile time? I am assumingattribute of"length" here is a static member variable. After all, we do not want to have to add a member variable every time we want to classify anwhatevera class.It's turned into one line of code at maximum at compile time. Should be using interfaces to indicate compliance instead, really.Another question, this looks to me like reflection, introspection,containeryou want to call it. In D, will this information be available at both run-time and compile-time? I can see applications for compile-time reflection and run-time reflection. Is there also an API to get amethod?of member methods, or a container member variables? An is_class()resolved atis_basic_type() method? If this API is in existence, and can beforcompile-time, then perhaps this is just the solution I have been lookinginto solve all my generic programming problems.It will be in the future, at least for runtime. Nic's brought up the case of ... disjoint typelist genericism. Or something. My opinion is that once those issues kick into gear, not using methods to do this is criminal, particularly as using generic methods with super allows even more flexibility in doing this.Smalltalk has also been tossed around here on occasion, but I don't think anyone's described it and I can't google any information about it.Sorry, I don't know anything about Smalltalk, so I can't comment. Sounds to me like you are totally on the right track here. Perhaps compile-time reflection will more elegantly resolve many current issuestemplates soregard to generics. I guess my main concern is how well the compiler is able to resolve things at compile-time. This is what makes C++gives mepowerful. More concise, maintainable source code with absolutely no run-time overhead, because the compiler does all the work. Are you involved with the D compiler development? If you are, thismore confidence in D. Do you have specs for your implementation of generics?Nope and nope. The generics stuff is just a shorthand at the moment - I haven't thought about how it would behave. But how about this. For generic functions and generic class methods, a "$" followed by an identifier in the place where a type would exist indicates a generic type. The specific type of this generic is determined by the first argument using it; a function cannot return a generic type only. For example: $type foo ($type a, $type b) $type bar (int c); /* Illegal */ complex x = foo (4, 2.3); /* Returns int and casts 2.3 to int */ Generic values are also prefixed with a $ and must be trivially constant. Generic values of type "TypeInfo" or "ClassInfo" are special in that they can be used both as a value and a generic type, and if so must be the first argument to use this generic value: $type cast (TypeInfo $type, $type value) { return value; } $type tsac ($type value, TypeInfo $type) /* Illegal */ cast (int, 4.3); /* Returns 4 */ A generic function that takes only generic types and values and only accesses other similarly compile-time values is considered trivially constant and must be folded. The generic function for a given function name and number of arguments is searched for eligibility after any specific-type functions. There can't be two generic functions with the same name and number of arguments as it's easy to make the overloading rules go crazy, and this restriction can be relaxed in the future. On to struct, class, and union. I've only taken the most obvious choice: struct Vector (TypeInfo $type, int $size) { $type [$size] array; } Vector (float, 4) x; struct Vector2 (TypeInfo $type) : Vector ($type, 2) { float x () { return array [0]; } float y () { return array [1]; } } struct Vector3 (TypeInfo $type) : Vector2 ($type) { float z () { return array [2]; } void z (float v) { array [2] = v; } } Vector3 (float) v; v.z = 16; Perhaps not Vector2 and Vector3, but the possibilities intrigue me. I _think_ the ambiguities that C++ was fighting against are nullified by D, which would be very good, as <> is not. I have also been thinking about making the generic values as a kind of virtual field and specifying their value in the constructor, but a usable syntax has not emerged. So in total it's just C++'s templates without the template keyword.
Jun 27 2002
Burton, I've been thinking about your approach for generic functions. How would your syntax handle this C++ template: template <int a, int b> float[b][a] Inverse(float matrix[a][b]) { ... } Perhaps you have a radically new idea that can handle this. Craig
Jun 27 2002
Burton, I've been thinking about your approach for generic functions. How would your syntax handle this C++ template: template <int a, int b> float[b][a] Inverse(float matrix[a][b]) { ... } Perhaps you have a radically new idea that can handle this. CraigI am going to answer my own question. void Invert(in $M matrix, out &I inverse) in { assert(constant(matrix.rows == inverse.cols)); assert(constant(matrix.cols == inverse.rows)); } body { ... } Given that there are row and column properties for the matrix, or some way of getting that information at compile time.
Jun 27 2002
"Craig Black" <cblack ara.com> wrote in message news:affqjc$2kbf$1 digitaldaemon.com...Still, in order to make this work completely at compile time, the function's contract should be part of the official interface of the function. The "template<>" (or, in LX, "generic[]", or Haskell's class assertions and contexts) construct is more robust in the general case. It's like saying... "assuming we have a and b which are integer values, this is a generic matrix-inverting function". It's clean, it's non-ambiguous. Of course, using angle brackets IS ambiguous for parsing (eek!), but that's besides the point. Salutaciones, JCABBurton, I've been thinking about your approach for generic functions. How would your syntax handle this C++ template: template <int a, int b> float[b][a] Inverse(float matrix[a][b]) { ... } Perhaps you have a radically new idea that can handle this. CraigI am going to answer my own question. void Invert(in $M matrix, out &I inverse) in { assert(constant(matrix.rows == inverse.cols)); assert(constant(matrix.cols == inverse.rows)); } body { ... } Given that there are row and column properties for the matrix, or some way of getting that information at compile time.
Jun 27 2002
Craig Black wrote:I've been thinking about your approach for generic functions. How would your syntax handle this C++ template: template <int a, int b> float[b][a] Inverse(float matrix[a][b]) { ... }float[$b][$a] Inverse (float matrix[$a][$b]) { ... } They're generic values of type int. But this is your one and only chance to have a generic function of this name and number of arguments in this scope, so a method is a much better solution. Before it comes up: foo (int [TypeInfo $type] bar) For associated arrays.Perhaps you have a radically new idea that can handle this.No, just an undescribed part of the syntax. I meant to describe it but forgot.
Jun 27 2002
float[$b][$a] Inverse (float matrix[$a][$b]) { ... }So in a generic function the $symbol can be a type, or an integer, or anything else? I could see where this ambiguity might be too much for the compiler to handle. That is why C++ uses "template<>" for functions. For classes I think its unnecessary, but for functions the compiler has to infer what the type or value is, so it is best to give the compiler as many hints as possible to reduce ambiguity. It would be different if we assumed that all $symbol's were types. How about preceding each $symbol with a type where the value is to be deduced? Not only will this specify what the type is, but it will tell the compiler which parameter to get the value from. I admit I've never designed a compiler, but I assume these kinds of generic functions are difficult to implement. Let's keep in mind that somebody is going to have to implement this stuff if it's ever going to work. float[$b][$a] Inverse (float matrix[int $a][int $b]) { ... }
Jun 28 2002
Array subscripts are always integral (and unsigned!) so one could leave out the "int" there, it's implicitly uint. $f[#b][#a] Inverse ($f matrix[#a][#b]) { ... } Sean "Craig Black" <cblack ara.com> wrote in message news:afhrmp$1v65$1 digitaldaemon.com...inferfloat[$b][$a] Inverse (float matrix[$a][$b]) { ... }So in a generic function the $symbol can be a type, or an integer, or anything else? I could see where this ambiguity might be too much for the compiler to handle. That is why C++ uses "template<>" for functions. For classes I think its unnecessary, but for functions the compiler has towhat the type or value is, so it is best to give the compiler as manyhintsas possible to reduce ambiguity. It would be different if we assumed that all $symbol's were types. How about preceding each $symbol with a type where the value is to be deduced? Not only will this specify what thetypeis, but it will tell the compiler which parameter to get the value from.Iadmit I've never designed a compiler, but I assume these kinds of generic functions are difficult to implement. Let's keep in mind that somebody is going to have to implement this stuff if it's ever going to work. float[$b][$a] Inverse (float matrix[int $a][int $b]) { ... }
Jun 28 2002
Array subscripts are always integral (and unsigned!) so one could leaveoutthe "int" there, it's implicitly uint. $f[#b][#a] Inverse ($f matrix[#a][#b]) { ... } SeanThis would work if we assumed that all #symbol's were unsigned integers. But what about associative arrays? With an associative array, the subscript can be char[] or potentially any other type. We would need another symbol for every kind of type. Craig
Jun 28 2002
wrong about its ability to use uint implicitly in the array index situation. So I'd have to modify my example thusly: $f[#b][#a] Inverse ($f matrix[uint #a][uint #b]) { ... } any #value would have to have a type specified for it at least once (and all such declarations would have to match). If the compiler can figure out the type implicitly that's great, if not, it has to be specified. Sean "cblack01" <cblack01 cox.net> wrote in message news:afj697$9eo$1 digitaldaemon.com...subscriptArray subscripts are always integral (and unsigned!) so one could leaveoutthe "int" there, it's implicitly uint. $f[#b][#a] Inverse ($f matrix[#a][#b]) { ... } SeanThis would work if we assumed that all #symbol's were unsigned integers. But what about associative arrays? With an associative array, thecan be char[] or potentially any other type. We would need another symbol for every kind of type. Craig
Jun 29 2002
On Sat, 29 Jun 2002 11:49:40 -0700 "Sean L. Palmer" <seanpalmer earthlink.net> wrote:$f[#b][#a] Inverse ($f matrix[uint #a][uint #b]) { ... }I hate, by the way, especially its synatx =) Could we come with some more elegant decision? I wonder if even C++-style < > brackets could be used, and teach the compiler to hanle >> properly for templates?
Jun 29 2002
Pavel Minayev <evilone omen.ru> wrote in news:CFN374370467174768 news.digitalmars.com:On Sat, 29 Jun 2002 11:49:40 -0700 "Sean L. Palmer" <seanpalmer earthlink.net> wrote:How about something like this. template { // Define parametric types type T1; type T2; uint XA; uint YA; uint XB; uint YB; // Define families of parametric fuctions // and structures T1[YA][XA] Inverse(T1[XA][YA] matrix) { } T1[XB][YA] Multipy(T1[XA][YA] m1,T1[XB][YB] m2) {} // struct foo(T1,T2) { T1[T2] bar; T1 func { } } }$f[#b][#a] Inverse ($f matrix[uint #a][uint #b]) { ... }I hate, by the way, especially its synatx =) Could we come with some more elegant decision? I wonder if even C++-style < > brackets could be used, and teach the compiler to hanle >> properly for templates?
Jun 29 2002
On Sat=2C 29 Jun 2002 22=3A25=3A55 +0000 =28UTC=29 Patrick Down =3Cpat=40codemoon=2Ecom=3E wrote=3A =3E How about something like this=2E =3E =3E template =3E { =3E =2F=2F Define parametric types =3E type T1=3B =3E type T2=3B =3E uint XA=3B =3E uint YA=3B =3E uint XB=3B =3E uint YB=3B =3E =3E =2F=2F Define families of parametric fuctions =3E =2F=2F and structures =3E =3E T1=5BYA=5D=5BXA=5D Inverse=28T1=5BXA=5D=5BYA=5D matrix=29 { } =3E =3E T1=5BXB=5D=5BYA=5D Multipy=28T1=5BXA=5D=5BYA=5D m1=2CT1=5BXB=5D=5BYB=5D m2=29 {} =3E =3E =2F=2F =3E struct foo=28T1=2CT2=29 =3E { =3E T1=5BT2=5D bar=3B =3E =3E T1 func { } =3E } =3E } Then how do you declare an instance of foo=3F Like this=3F =09foo=28char=5B=5D=2C int=29 x=3B Looks too much like a function pointer =28or delegate=29=2E I think a distinct syntax is still needed=2E
Jun 30 2002
Well this at least has a look that fits with the rest of D quite nicely. I agree with Pavel, I don't like the () syntax ... something else is needed. In fact the below doesn't even really need the (T1,T2) part in struct foo(T1,T2) as it's already well known that T1 and T2 are generic types since the whole thing is within a template{} declaration that defines T1 and T2. Perhaps you could name the template scope and instantiate the template scope with some special syntax to access the identifiers of the templated types? template T1 { type T; T min(T a, T b) { return (a<b) ? a : b; } } void main() { int x,y; return T1(int T).min(x,y); } Sean "Patrick Down" <pat codemoon.com> wrote in message news:Xns923CB3E63DC17patcodemooncom 63.105.9.61...Pavel Minayev <evilone omen.ru> wrote in news:CFN374370467174768 news.digitalmars.com:On Sat, 29 Jun 2002 11:49:40 -0700 "Sean L. Palmer" <seanpalmer earthlink.net> wrote:How about something like this. template { // Define parametric types type T1; type T2; uint XA; uint YA; uint XB; uint YB; // Define families of parametric fuctions // and structures T1[YA][XA] Inverse(T1[XA][YA] matrix) { } T1[XB][YA] Multipy(T1[XA][YA] m1,T1[XB][YB] m2) {} // struct foo(T1,T2) { T1[T2] bar; T1 func { } } }$f[#b][#a] Inverse ($f matrix[uint #a][uint #b]) { ... }I hate, by the way, especially its synatx =) Could we come with some more elegant decision? I wonder if even C++-style < > brackets could be used, and teach the compiler to hanle >> properly for templates?
Jun 30 2002
If D source could use Unicode characters, we could use French quotation marks << and >> for shifts, and < and > for templates. ;) you're dealing with generic types or values. Sean "Pavel Minayev" <evilone omen.ru> wrote in message news:CFN374370467174768 news.digitalmars.com...On Sat, 29 Jun 2002 11:49:40 -0700 "Sean L. Palmer"<seanpalmer earthlink.net>wrote:$f[#b][#a] Inverse ($f matrix[uint #a][uint #b]) { ... }I hate, by the way, especially its synatx =) Could we come with some more elegant decision? I wonder if even C++-style < > brackets could be used, and teach the compiler to hanle >> properly for templates?
Jun 30 2002
Craig Black wrote: >> float[$b][$a] Inverse (float matrix[$a][$b]) { ... } > > So in a generic function the $symbol can be a type, or an integer, or > anything else? I could see where this ambiguity might be too much for the > compiler to handle. That is why C++ uses "template<>" for functions. For > classes I think its unnecessary, but for functions the compiler has to infer > what the type or value is, so it is best to give the compiler as many hints > as possible to reduce ambiguity. It would be different if we assumed that > all $symbol's were types. How about preceding each $symbol with a type > where the value is to be deduced? Not only will this specify what the type > is, but it will tell the compiler which parameter to get the value from. I > admit I've never designed a compiler, but I assume these kinds of generic > functions are difficult to implement. Let's keep in mind that somebody is > going to have to implement this stuff if it's ever going to work. Compiler-wise this matter is trivial (functions anyway); I wouldn't recommend it if I knew otherwise. For divining matches you'd merely take the call and cycle through the arguments, filling in as you walk along. Then create a signature out of it, and if it matches the arguments and has not been compiled do so. There's a good set of very well-defined steps for getting there from here. $ defines new mandatory trivial constant folding points to put it in its purest term. Couple hundred lines of code max. Blarg. I'm trying to figure out what kind of monster struct, class, and union would turn out to be if it could have specific values passed to its factory. This is haunting me: struct Matrix (TypeInfo $type, int rows, int cols) { $type [rows] [cols] array; } Matrix (float, 4, 4) foo; /* constant size */ Matrix (Color, h, w) bar; /* run-time sized using alloca */ struct Moof { Matrix (int) m; } Moof moof; moof.m = Matrix (int, h, w); I don't like the last part of the syntax which has some weird internal gymnastics and odd syntax. Maybe: struct Moof (int rows, int cols) { Matrix (int, rows, cols) m; } Moof (h, w) moof; But I don't like things propagating like this, even if it is consistent with templates. Hm. > float[$b][$a] Inverse (float matrix[int $a][int $b]) { ... } This is redundant. I don't particularly care how it goes - it's just that allowing "int $a" implies that you can do "float $a", and it's kind of confusing that "[int $a]" and "[int]" mean entirely different things. At least "(int $a)" and "(int)" are within speaking distance.
Jun 29 2002
Compiler-wise this matter is trivial (functions anyway); I wouldn't recommend it if I knew otherwise. For divining matches you'd merely take the call and cycle through the arguments, filling in as you walk along. Then create a signature out of it, and if it matches the arguments and has not been compiled do so. There's a good set of very well-defined steps for getting there from here. $ defines new mandatory trivial constant folding points to put it in its purest term. Couple hundred lines of code max.OK. Sounds like you know what you're talking about. Just to clarify in my mind, what is the justification for ditching the "template <>" or "generic []" syntax for generic functions? Is this just unnecessary?Blarg. I'm trying to figure out what kind of monster struct, class, and union would turn out to be if it could have specific values passed to its factory. This is haunting me: struct Matrix (TypeInfo $type, int rows, int cols) { $type [rows] [cols] array; } Matrix (float, 4, 4) foo; /* constant size */ Matrix (Color, h, w) bar; /* run-time sized using alloca */ struct Moof { Matrix (int) m; } Moof moof; moof.m = Matrix (int, h, w); I don't like the last part of the syntax which has some weird internal gymnastics and odd syntax. Maybe: struct Moof (int rows, int cols) { Matrix (int, rows, cols) m; } Moof (h, w) moof; But I don't like things propagating like this, even if it is consistent with templates. Hm.Ouch! This stuff is starting to make my brain hurt. Are you trying to find a syntax that can instantiate a generic at run-time? What would we get if we removed the $ from "$type" in this template. A run-time generic? Is this what you are trying to accomplish? If so, perhaps we could use the same syntax for both run-time and compile-time. The same generic could be instantiated at compile-time or run-time. That way you wouldn't have to duplicate any code in order to have both compile-time and run-time generics.> float[$b][$a] Inverse (float matrix[int $a][int $b]) { ... } This is redundant. I don't particularly care how it goes - it's just that allowing "int $a" implies that you can do "float $a", and it's kind of confusing that "[int $a]" and "[int]" mean entirely different things. At least "(int $a)" and "(int)" are within speaking distance.float[$b][$a] Inverse (float matrix[$a][$b]) { ... } Hey, if the compiler doesn't mind, neither do I.
Jul 01 2002
"Burton Radons" <loth users.sourceforge.net> wrote in message news:3D1AD1CD.3080308 users.sourceforge.net...I _think_ the ambiguities that C++ was fighting against are nullified by D, which would be very good, as <> is not.That's some of the problem with C++ templates. The rest of the complexities come about because of implicit instantiation. If, instead, things are explicitly instantiated, most of the complexity goes away. None of the rules about partial ordering, etc., would be necessary.
Jul 03 2002
That could also suck alot of the ease-of-use out of them. Would mean writing every declaration of a generic type in at least two places. Ok, most of the time in C++ we do this anyway using a typedef, but when splicing together expressions etc it's convenient to not have to manually instantiate them. Sean "Walter" <walter digitalmars.com> wrote in message news:afvs5u$2lce$1 digitaldaemon.com..."Burton Radons" <loth users.sourceforge.net> wrote in message news:3D1AD1CD.3080308 users.sourceforge.net...complexitiesI _think_ the ambiguities that C++ was fighting against are nullified by D, which would be very good, as <> is not.That's some of the problem with C++ templates. The rest of thecome about because of implicit instantiation. If, instead, things are explicitly instantiated, most of the complexity goes away. None of therulesabout partial ordering, etc., would be necessary.
Jul 05 2002
"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:ag40dh$mc2$1 digitaldaemon.com...That could also suck alot of the ease-of-use out of them. Would mean writing every declaration of a generic type in at least two places. Ok, most of the time in C++ we do this anyway using a typedef, but whensplicingtogether expressions etc it's convenient to not have to manuallyinstantiatethem.I know it's convenient when it works, but I don't believe it's worth it. When there are a bunch of partially specialized templates spread all over the header files, don't you find yourself wondering sometimes which is getting picked, and then trying to figure out an easy way to verify it? If your code is working, there's no problem, but if it isn't or it needs enhancement, I just don't think the obfuscation is saving any programming effort. What I see for D is what you say, basically enshrining the typedef approach as the way to instantiate a template.
Jul 05 2002
That will work. And it'll be simple and elegant. It just might be a teeny bit inconvenient as it will prevent expression-style programming without having to put typedefs beforehand. in STL C++: #include <list> #include <algorithm> list<int> intlist; sort(intlist.begin(), intlist.end(), less<int>()); in D: something like import list; import algorithm; typedef list{int} list_of_int; list_of_int intlist; typedef less{int} less_for_int; typedef sort{int, list_of_int.iterator_type, less_for_int} sort_routine; sort_routine(intlist.begin(), intlist.end(), less_for_int()); As you can see, it's not nearly as elegant when you have to typedef everything. This is just one teensy example; I've seen really cool stuff done this way: Check out http://spirit.sourceforge.net for a cool example of the power of C++ templates when combined with operator overloading. Maybe you could make it work so that if you fully spell out the type it can be instantiated in an expression. I suppose this can be added later without much problem, so if it turns out to be impractical it can be fixed later. Something like: import list; import algorithm; list{int} intlist; sort{int, list{int}.iterator_type, less{int}}(intlist.begin(), intlist.end()); But in reality I'd rather the standard templated containers be safer than STL iterator-based containers, perhaps something that functions more like a dynamic array? It'll be tough to make a linked list behave like a dynamic array though. The algorithmic performance characteristics and the preferred usage patterns are completely different. Perhaps the dynamic array reallocation problem can be solved by making a dynamic array actually a container of pointers to subranges of the array. So if it needs expanded and the memory can't be resized in place, it just allocates a new block and doesn't copy the old one. That would make dynamic array access have to go through one more level of indirection and you couldn't typecast it to a pointer to a flat array anymore (maybe a function to "flatten" a dynamic array would be good) but it would solve most of the "for (ever) myarray ~= asingleentry;" problem. Sean "Walter" <walter digitalmars.com> wrote in message news:ag4kct$1bdq$3 digitaldaemon.com..."Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:ag40dh$mc2$1 digitaldaemon.com...approachThat could also suck alot of the ease-of-use out of them. Would mean writing every declaration of a generic type in at least two places. Ok, most of the time in C++ we do this anyway using a typedef, but whensplicingtogether expressions etc it's convenient to not have to manuallyinstantiatethem.I know it's convenient when it works, but I don't believe it's worth it. When there are a bunch of partially specialized templates spread all over the header files, don't you find yourself wondering sometimes which is getting picked, and then trying to figure out an easy way to verify it? If your code is working, there's no problem, but if it isn't or it needs enhancement, I just don't think the obfuscation is saving any programming effort. What I see for D is what you say, basically enshrining the typedefas the way to instantiate a template.
Jul 05 2002
Yes I know it'll be more typing. Perhaps I can find a way to reduce that without doing the implicit instantiation two-step. There's another maddening example of the implict instantiation resulting in bizarre rules - the way dependent and non-dependent names are looked up. The non-dependent names are looked up in an earlier version of the global symbol table than the dependent names are. Perhaps this makes sense to someone, but to me it's just a way to torture compiler writers <g>. "Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:ag4q05$1grg$1 digitaldaemon.com...That will work. And it'll be simple and elegant. It just might be a teeny bit inconvenient as it will prevent expression-style programming without having to put typedefs beforehand. in STL C++: #include <list> #include <algorithm> list<int> intlist; sort(intlist.begin(), intlist.end(), less<int>()); in D: something like import list; import algorithm; typedef list{int} list_of_int; list_of_int intlist; typedef less{int} less_for_int; typedef sort{int, list_of_int.iterator_type, less_for_int}sort_routine;sort_routine(intlist.begin(), intlist.end(), less_for_int()); As you can see, it's not nearly as elegant when you have to typedef everything. This is just one teensy example; I've seen really cool stuff done this way: Check out http://spirit.sourceforge.net for a cool example of the power of C++ templates when combined with operator overloading. Maybe you could make it work so that if you fully spell out the type itcanbe instantiated in an expression. I suppose this can be added laterwithoutmuch problem, so if it turns out to be impractical it can be fixed later. Something like: import list; import algorithm; list{int} intlist; sort{int, list{int}.iterator_type, less{int}}(intlist.begin(), intlist.end()); But in reality I'd rather the standard templated containers be safer than STL iterator-based containers, perhaps something that functions more likeadynamic array? It'll be tough to make a linked list behave like a dynamic array though. The algorithmic performance characteristics and thepreferredusage patterns are completely different. Perhaps the dynamic array reallocation problem can be solved by making a dynamic array actually a container of pointers to subranges of the array. So if it needs expanded and the memory can't be resized in place, it just allocates a new block and doesn't copy the old one. That would makedynamicarray access have to go through one more level of indirection and you couldn't typecast it to a pointer to a flat array anymore (maybe afunctionto "flatten" a dynamic array would be good) but it would solve most of the "for (ever) myarray ~= asingleentry;" problem.
Jul 05 2002
"Walter" <walter digitalmars.com> wrote in message news:ag5bvm$227j$1 digitaldaemon.com...maddeningAs you can see, it's not nearly as elegant when you have to typedef everything.Yes I know it'll be more typing. Perhaps I can find a way to reduce that without doing the implicit instantiation two-step. There's anotherexample of the implict instantiation resulting in bizarre rules - the way dependent and non-dependent names are looked up. The non-dependent namesarelooked up in an earlier version of the global symbol table than the dependent names are.Yes, the non-dependent names are looked up at the point where the template is defined, and the dependent names are looked up at the point the template is instantiated. But how could this be different? Unless you enforce the explicit enumeration of all allowed instances at the point where the template is defined, or somehow store a snapshot of the symbol tables at the point the template was defined, you still need to match names at the point of instantiation. And those alternatives do not sound reasonable to me.Perhaps this makes sense to someone, but to me it's just a way to torture compiler writers <g>.What alternative could there be? Looking up _all_ names at the point of instantiation? I'm really curious. Or am I missing something here? Salutaciones, JCAB
Jul 05 2002
"Juan Carlos Arevalo Baeza" <jcab roningames.com> wrote in message news:ag5j9q$29lv$1 digitaldaemon.com...Yes, the non-dependent names are looked up at the point where the template is defined, and the dependent names are looked up at the pointthetemplate is instantiated. But how could this be different? Unless you enforce the explicit enumeration of all allowed instances at the pointwherethe template is defined, or somehow store a snapshot of the symbol tablesatthe point the template was defined, you still need to match names at the point of instantiation. And those alternatives do not sound reasonable to me.The DMC++ compiler collects the template definition as a list of tokens, and then inserts it into the source at the point of instantiation. So, all symbol table lookups are done at the point of instantiation. I believe that is a much more understandable rule (easy to explain) than the confusing and subtle difference in behavior between dependent and non-dependent names.Perhaps this makes sense to someone, but to me it's just a way to torture compiler writers <g>.What alternative could there be? Looking up _all_ names at the point of instantiation? I'm really curious. Or am I missing something here?
Jul 07 2002
I don't believe the scoping rules would work with that scheme, would it? Like treating an inline function as a pure macro expansion, it just doesn't have the right semantics. Sean "Walter" <walter digitalmars.com> wrote in message news:agajj6$1h6g$1 digitaldaemon.com..."Juan Carlos Arevalo Baeza" <jcab roningames.com> wrote in message news:ag5j9q$29lv$1 digitaldaemon.com...tablesYes, the non-dependent names are looked up at the point where the template is defined, and the dependent names are looked up at the pointthetemplate is instantiated. But how could this be different? Unless you enforce the explicit enumeration of all allowed instances at the pointwherethe template is defined, or somehow store a snapshot of the symbolattothe point the template was defined, you still need to match names at the point of instantiation. And those alternatives do not sound reasonableofme.Perhaps this makes sense to someone, but to me it's just a way to torture compiler writers <g>.What alternative could there be? Looking up _all_ names at the pointandinstantiation? I'm really curious. Or am I missing something here?The DMC++ compiler collects the template definition as a list of tokens,then inserts it into the source at the point of instantiation. So, all symbol table lookups are done at the point of instantiation. I believethatis a much more understandable rule (easy to explain) than the confusingandsubtle difference in behavior between dependent and non-dependent names.
Jul 08 2002
"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:agbegl$2bll$1 digitaldaemon.com...I don't believe the scoping rules would work with that scheme, would it? Like treating an inline function as a pure macro expansion, it justdoesn'thave the right semantics.I neglected to mention that only the global namespace and the current namespace(s) are included in the instantiation symbol lookups.
Jul 08 2002
Seems like it should only have access to: 1) The symbols available at the point of template declaration 2) The symbols injected into the template as template parameters 3) Symbols local to the template Sean "Walter" <walter digitalmars.com> wrote in message news:agcei2$aln$2 digitaldaemon.com..."Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:agbegl$2bll$1 digitaldaemon.com...I don't believe the scoping rules would work with that scheme, would it? Like treating an inline function as a pure macro expansion, it justdoesn'thave the right semantics.I neglected to mention that only the global namespace and the current namespace(s) are included in the instantiation symbol lookups.
Jul 08 2002
"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:agclqa$iaq$1 digitaldaemon.com...Seems like it should only have access to: 1) The symbols available at the point of template declaration 2) The symbols injected into the template as template parameters 3) Symbols local to the template SeanTo me either the symbols from the point of declaration or the point of instantiation, not a mish-mash of both.
Jul 09 2002
"Walter" <walter digitalmars.com> wrote in news:age1p7$1vei$2 digitaldaemon.com:"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:agclqa$iaq$1 digitaldaemon.com...Symbols from the point of declaration whould fit the function model best. In a function I can use values passed in as parameters, values in my current global namespace or object namespace at the point of definition. However taking symbols from the point of instantiation could be quite interesting. Could a function declared outside of an object be used as a member function? I don't know what our template syntax will be so I'll just make it up. :-) template<> char[] getName() { return name; } class foo { char[] name; } class bar { char[] name; } a = new foo; b = new bar; a.getName(); b.getName(); Or, better yet, if you require explicit instantiation. class foo { char[] name; templatedef getName(); // foo now has GetName member; }Seems like it should only have access to: 1) The symbols available at the point of template declaration 2) The symbols injected into the template as template parameters 3) Symbols local to the template SeanTo me either the symbols from the point of declaration or the point of instantiation, not a mish-mash of both.
Jul 09 2002
Hmm. I don't think that should work! "Patrick Down" <pat codemoon.com> wrote in message news:Xns9246524F06ABDpatcodemooncom 63.105.9.61..."Walter" <walter digitalmars.com> wrote in news:age1p7$1vei$2 digitaldaemon.com:"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:agclqa$iaq$1 digitaldaemon.com...Symbols from the point of declaration whould fit the function model best. In a function I can use values passed in as parameters, values in my current global namespace or object namespace at the point of definition. However taking symbols from the point of instantiation could be quite interesting. Could a function declared outside of an object be used as a member function? I don't know what our template syntax will be so I'll just make it up. :-) template<> char[] getName() { return name; } class foo { char[] name; } class bar { char[] name; } a = new foo; b = new bar; a.getName(); b.getName(); Or, better yet, if you require explicit instantiation. class foo { char[] name; templatedef getName(); // foo now has GetName member; }Seems like it should only have access to: 1) The symbols available at the point of template declaration 2) The symbols injected into the template as template parameters 3) Symbols local to the template SeanTo me either the symbols from the point of declaration or the point of instantiation, not a mish-mash of both.
Jul 09 2002
"Walter" <walter digitalmars.com> wrote in news:agf4b6$ho7$2 digitaldaemon.com:Hmm. I don't think that should work! "Patrick Down" <pat codemoon.com> wrote in message news:Xns9246524F06ABDpatcodemooncom 63.105.9.61...Well even I will admit that the attaching a template function like above is pretty silly."Walter" <walter digitalmars.com> wrote in news:age1p7$1vei$2 digitaldaemon.com: However taking symbols from the point of instantiation could be quite interesting. Could a function declared outside of an object be used as a member function? I don't know what our template syntax will be so I'll just make it up. :-) template<> char[] getName() { return name; } class foo { char[] name; } class bar { char[] name; } a = new foo; b = new bar; a.getName(); b.getName();However the explicit template instantiation above has some merit I think. It's a way to implement mixins.Or, better yet, if you require explicit instantiation. class foo { char[] name; templatedef getName(); // foo now has GetName member; }
Jul 09 2002
"Walter" <walter digitalmars.com> wrote in message news:agf4b6$ho7$2 digitaldaemon.com..."Patrick Down" <pat codemoon.com> wrote in message news:Xns9246524F06ABDpatcodemooncom 63.105.9.61...template< class T > char[] T::getName() { return name; } As far as expressivity is concerned, this type of thing should be doable. It's definitely no more ambiguous than operator overloading in C++. Salutaciones, JCABI don't know what our template syntax will be so I'll just make it up. :-) template<> char[] getName() { return name; } ...Hmm. I don't think that should work!
Jul 09 2002
And if T didn't have a name member, it would be an error to try to instantiate getName(). No harm done though. That's probably exactly the desired behavior. Sean "Juan Carlos Arevalo Baeza" <jcab roningames.com> wrote in message news:agfebn$r98$1 digitaldaemon.com..."Walter" <walter digitalmars.com> wrote in message news:agf4b6$ho7$2 digitaldaemon.com...doable."Patrick Down" <pat codemoon.com> wrote in message news:Xns9246524F06ABDpatcodemooncom 63.105.9.61...template< class T > char[] T::getName() { return name; } As far as expressivity is concerned, this type of thing should beI don't know what our template syntax will be so I'll just make it up. :-) template<> char[] getName() { return name; } ...Hmm. I don't think that should work!It's definitely no more ambiguous than operator overloading in C++. Salutaciones, JCAB
Jul 09 2002
Then I would pick the point of declaration; however you still need to be able to "inject" symbols via template parameters that aren't otherwise available at the point of template declaration. The template writer has no idea what symbols will be available at point of instantiation and cannot rely on having all its needed symbols present. So point of instantiation seems like a bad choice. Sean "Walter" <walter digitalmars.com> wrote in message news:age1p7$1vei$2 digitaldaemon.com..."Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:agclqa$iaq$1 digitaldaemon.com...Seems like it should only have access to: 1) The symbols available at the point of template declaration 2) The symbols injected into the template as template parameters 3) Symbols local to the template SeanTo me either the symbols from the point of declaration or the point of instantiation, not a mish-mash of both.
Jul 09 2002
"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:agf4m8$i7u$1 digitaldaemon.com..."Walter" <walter digitalmars.com> wrote in message news:age1p7$1vei$2 digitaldaemon.com...SoTo me either the symbols from the point of declaration or the point of instantiation, not a mish-mash of both.Then I would pick the point of declaration; however you still need to be able to "inject" symbols via template parameters that aren't otherwise available at the point of template declaration. The template writer has no idea what symbols will be available at point of instantiation and cannot rely on having all its needed symbols present.point of instantiation seems like a bad choice.Hmmm... I'm thinking... This would not be a problem is the following applies: - The language is structurally unambiguous. So you know what is a function call, a declaration, etc... without doing symbol lookup. - The overloading resolution is done at link time. This would mean the syntax would have to differ from C/C++ more significantly, and a big portion of the code generation would move to the linker. Not for D, I suppose, but interesting nonetheless. Salutaciones, JCAB
Jul 09 2002
"Juan Carlos Arevalo Baeza" <jcab roningames.com> wrote in message news:agfek2$roc$1 digitaldaemon.com...Hmmm... I'm thinking... This would not be a problem is the following applies: - The language is structurally unambiguous. So you know what is a function call, a declaration, etc... without doing symbol lookup. - The overloading resolution is done at link time. This would mean the syntax would have to differ from C/C++ more significantly, and a big portion of the code generation would move to the linker. Not for D, I suppose, but interesting nonetheless. Salutaciones, JCABExactly. Move most of the actual code generation to *after* linking. Some optimization could be done on the parse tree ahead of time, but the brunt should be done after link, when everything aside from dynamic linkage is execution time. That's not a bad idea either but it requires more runtime support, and could take a little time, which is bad for many classes of apps. At least it should only have to be done once per app per machine. I wonder if anyone has really taken a step back from the lex/parse/semantic/codegen/link design we've had for several decades and tried to design a better way? Surely some improvements could be made. Sean
Jul 09 2002
"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:agghgk$1uis$1 digitaldaemon.com..."Juan Carlos Arevalo Baeza" <jcab roningames.com> wrote in message news:agfek2$roc$1 digitaldaemon.com...theThis would mean the syntax would have to differ from C/C++ more significantly, and a big portion of the code generation would move toSomelinker. Not for D, I suppose, but interesting nonetheless.Exactly. Move most of the actual code generation to *after* linking.optimization could be done on the parse tree ahead of time, but the brunt should be done after link, when everything aside from dynamic linkage is known.Interestingly, this would make the "export" support in C++ trivial...execution time. That's not a bad idea either but it requires more runtime support, and could take a little time, which is bad for many classes of apps. At least it should only have to be done once per app per machine.Yes, their JIT system is actually very impressive, but a bit overkill for some cases. You'd never want to use something like that on a Playstation 2...I wonder if anyone has really taken a step back from the lex/parse/semantic/codegen/link design we've had for several decades and tried to design a better way? Surely some improvements could be made.I'm experimenting along those lines... :) Salutaciones, JCAB
Jul 10 2002
"Walter" <walter digitalmars.com> wrote in message news:agajj6$1h6g$1 digitaldaemon.com..."Juan Carlos Arevalo Baeza" <jcab roningames.com> wrote in message news:ag5j9q$29lv$1 digitaldaemon.com...ofWhat alternative could there be? Looking up _all_ names at the pointandinstantiation? I'm really curious. Or am I missing something here?The DMC++ compiler collects the template definition as a list of tokens,then inserts it into the source at the point of instantiation. So, all symbol table lookups are done at the point of instantiation. I believethatis a much more understandable rule (easy to explain) than the confusingandsubtle difference in behavior between dependent and non-dependent names.It's simpler to explain, but it differs from the normal behavior of lookups. As in: --- void func(int) {} template < class T > void tfunc() { func('a'); } void func(char) {} int main() { tfunc<float>(); // calls func(char) return 0; } --- where if tfunc() is made non-template, it'll call func(int) instead. The distinction between dependent and non-dependent names is meant to lessen that difference. That makes it quite obviously good, IMHO. It does make the compiler harder to make, though, I'll agree to that :) Your solution is elegantly simple. I assume you'll make it "the law" for D's generics when it comes to that. Salutaciones, JCAB
Jul 08 2002
"Juan Carlos Arevalo Baeza" <jcab roningames.com> wrote in message news:agcmvq$jjf$1 digitaldaemon.com...It does make the compiler harder to make, though, I'll agree to that :) Your solution is elegantly simple. I assume you'll make it "the law" forD'sgenerics when it comes to that.D does it one better. The symbol table is generated before the templates are processed, so all the symbols in the file are available, not just the ones lexically preceding it.
Jul 09 2002
sweet but hopefully there's some rule about what scope the template instantiation uses Perhaps it can first try to use the scope of its declaration and if that fails, try the scope of the point of instantiation Sean "Walter" <walter digitalmars.com> wrote in message news:age66h$24qt$1 digitaldaemon.com..."Juan Carlos Arevalo Baeza" <jcab roningames.com> wrote in message news:agcmvq$jjf$1 digitaldaemon.com...:)It does make the compiler harder to make, though, I'll agree to thatareYour solution is elegantly simple. I assume you'll make it "the law" forD'sgenerics when it comes to that.D does it one better. The symbol table is generated before the templatesprocessed, so all the symbols in the file are available, not just the ones lexically preceding it.
Jul 09 2002
Yeah, that will require some careful thought. -Walter "Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:agf4ib$i2h$1 digitaldaemon.com...sweet but hopefully there's some rule about what scope the templateinstantiationuses Perhaps it can first try to use the scope of its declaration and if that fails, try the scope of the point of instantiation Sean
Jul 09 2002
"Walter" <walter digitalmars.com> wrote in message news:age66h$24qt$1 digitaldaemon.com...D does it one better. The symbol table is generated before the templatesareprocessed, so all the symbols in the file are available, not just the ones lexically preceding it.Right! That makes it substantially better. Still see a problem with templates exported from a module and used in several other modules. Ironically, C/C++'s system of using textual include files for module handling makes this point pretty much moot. Personally, I don't think there's a perfect solution, no matter how you do it. Salutaciones, JCAB
Jul 09 2002
Yeah, it seems difficult. I never implemented generics before. You're like 15 steps ahead of me there. ;) Sean "Walter" <walter digitalmars.com> wrote in message news:ag5bvm$227j$1 digitaldaemon.com...Yes I know it'll be more typing. Perhaps I can find a way to reduce that without doing the implicit instantiation two-step. There's anothermaddeningexample of the implict instantiation resulting in bizarre rules - the way dependent and non-dependent names are looked up. The non-dependent namesarelooked up in an earlier version of the global symbol table than the dependent names are. Perhaps this makes sense to someone, but to me it's just a way to torture compiler writers <g>.
Jul 07 2002
"Burton Radons" <loth users.sourceforge.net> wrote in message news:3D17D5CE.3040608 users.sourceforge.net...Craig Black wrote:Imagine that Add for numerical and Add for containers are placed in different libraries and written by different authors. Then there is no way to unite then into one function you showed. Another example for using typelists is to restrict using template with some types. Of course, without using typelists you should get plenty of compiler errors when attempting to instantiate template for wrong type/class. Sometimes you can hardly understand what happenings. But I would like to have only one error: "type '...' is not suitable for template '..'". Nic Tiger.Then you could rewrite the Add function: template <typename T : NumericTypes> T Add(T a, T b) { return a + b; } template <typename T : ContainerTypes> T Add(T a, T b) { T result; result.append(a); result.append(b); return result; }That could easily become, using my generics methodology: $T Add ($T a, $T b) { if ($T.has_field ("length")) return a ~ b; else return a + b; } So I think you introduced a good idea - cswitch/cif/celse - and then didn't use it right when it would work great. Can you produce an example of code where typelist is necessary?
Jun 25 2002
Burton Radons <loth users.sourceforge.net> wrote in news:3D17D5CE.3040608 users.sourceforge.net:That could easily become, using my generics methodology: $T Add ($T a, $T b) { if ($T.has_field ("length")) return a ~ b; else return a + b; }I generally like this form of generics. It works well for generic fuctions but what about generic types? A tree of int or char[]? I have a rather crazy idea. What if we treated "type" as a type? type IntType = int; IntType b = 3; One of the things you could do with this is create functions that dealt with types. Here is a function that builds a binary tree type. type BinaryTree(type T) { struct Tree { T data; Tree left; Tree right; }; return Tree; } Another idea I have is that design by contract can be extended to deal type in generics. void Func($T a) in { // Make sure $T has a cmp function with the // correct signature assert($T.cmp && $T.cmp.type == (int (*)($T,$T))); } body { //... } This could help with some of the really bad error messages you see with C++ templates.Smalltalk has also been tossed around here on occasion, but I don't think anyone's described it and I can't google any information about it.There are more that one type of generic. Generic types. Generic functions. Generic algorthms. Smalltalk and Ruby are good languages to look at for how they do generic algorthms. Here is what I think people need to look at when doing generics. Take a look at the C++ STL. It is a good idea with a poor implementaion due to the the way C++ does templates. How can you do the same sorts of things in a way that is more understandable and easier to deal with?
Jun 25 2002
"Patrick Down" <pat codemoon.com> wrote in message news:Xns92385BBDDAE20patcodemooncom 63.105.9.61...Burton Radons <loth users.sourceforge.net> wrote in news:3D17D5CE.3040608 users.sourceforge.net:Isn't this very similar to typedef or alias?That could easily become, using my generics methodology: $T Add ($T a, $T b) { if ($T.has_field ("length")) return a ~ b; else return a + b; }I generally like this form of generics. It works well for generic fuctions but what about generic types? A tree of int or char[]? I have a rather crazy idea. What if we treated "type" as a type? type IntType = int;IntType b = 3; One of the things you could do with this is create functions that dealt with types. Here is a function that builds a binary tree type. type BinaryTree(type T) { struct Tree { T data; Tree left; Tree right; }; return Tree; }Things that make you go "Hmmm.....". Fundamentally type generics use "parametric types". You propose to introduce type syntax just as if it were a fundamental type. I'm not trying to shoot down this idea, but is there any reason do this? What then is the difference between the above and a template like this: struct Tree<$T> { $T data; Tree left; Tree right; };Another idea I have is that design by contract can be extended to deal type in generics. void Func($T a) in { // Make sure $T has a cmp function with the // correct signature assert($T.cmp && $T.cmp.type == (int (*)($T,$T))); } body { //... }That's a good idea. This would be a compile-time assertion. Perhaps we could have a "cassert" to denote this.This could help with some of the really bad error messages you see with C++ templates.Yes STL is good. How can we achieve the same functionality and performance with more understandable syntax and less code? More readability and greater genericity.Smalltalk has also been tossed around here on occasion, but I don't think anyone's described it and I can't google any information about it.There are more that one type of generic. Generic types. Generic functions. Generic algorthms. Smalltalk and Ruby are good languages to look at for how they do generic algorthms. Here is what I think people need to look at when doing generics. Take a look at the C++ STL. It is a good idea with a poor implementaion due to the the way C++ does templates. How can you do the same sorts of things in a way that is more understandable and easier to deal with?
Jun 25 2002
"Craig Black" <cblack ara.com> wrote in news:afa0ae$pm0$1 digitaldaemon.com:"Patrick Down" <pat codemoon.com> wrote in message news:Xns92385BBDDAE20patcodemooncom 63.105.9.61...Yes it is. But it's not all that weard C++ was forced to create a similar concept. template<class T> class X { typename T::Y; // treat Y as a type Y m_y; };Burton Radons <loth users.sourceforge.net> wrote in news:3D17D5CE.3040608 users.sourceforge.net:Isn't this very similar to typedef or alias?That could easily become, using my generics methodology: $T Add ($T a, $T b) { if ($T.has_field ("length")) return a ~ b; else return a + b; }I generally like this form of generics. It works well for generic fuctions but what about generic types? A tree of int or char[]? I have a rather crazy idea. What if we treated "type" as a type? type IntType = int;Fundamentally type generics use "parametric types". You propose to introduce type syntax just as if it were a fundamental type. I'm not trying to shoot down this idea, but is there any reason do this?Conditional data structure building, although I can't think of a good example right now. So I'll give a really bogas one. type BinaryTree(type T) { if(T == int) { struct Tree { T data; Tree left; Tree right; } return Tree; } else { struct Tree { T data; int key; Tree left; Tree right; } return Tree; } }Yes STL is good. How can we achieve the same functionality and performance with more understandable syntax and less code? More readability and greater genericity.Yes, with some care. One of the problems I think C++ templates has is that they use the same syntax to try to solve a a bunch of unrelated problems.
Jun 25 2002
Yes, with some care. One of the problems I think C++ templates has is that they use the same syntax to try to solve a a bunch of unrelated problems.Sorry that was't very clear. I mean that C++ uses the template syntax where other solutions might be more appropriate.
Jun 25 2002
Conditional data structure building, although I can't think of a good example right now. So I'll give a really bogas one. type BinaryTree(type T) { if(T == int) { struct Tree { T data; Tree left; Tree right; } return Tree; } else { struct Tree { T data; int key; Tree left; Tree right; } return Tree; } }How about allowing compile-time conditionals outside of function context: struct BinaryTree<$T> { T data; cif ($T != int) { int key; } Tree left; Tree right; };
Jun 25 2002
That's *very* close to the functionality of the current 'version' construct. Sean "Craig Black" <cblack ara.com> wrote in message news:afaljg$2t64$1 digitaldaemon.com...Conditional data structure building, although I can't think of a good example right now. So I'll give a really bogas one. type BinaryTree(type T) { if(T == int) { struct Tree { T data; Tree left; Tree right; } return Tree; } else { struct Tree { T data; int key; Tree left; Tree right; } return Tree; } }How about allowing compile-time conditionals outside of function context: struct BinaryTree<$T> { T data; cif ($T != int) { int key; } Tree left; Tree right; };
Jun 26 2002
Craig Black wrote:How about allowing compile-time conditionals outside of function context: struct BinaryTree<$T> { T data; cif ($T != int) { int key; } Tree left; Tree right; };Ignoring whether or not this is a good idea for the moment, I believe the syntax could be improved. Instead of using many new keywords (cif, cswitch) we could use a single keyword to inform the compiler the statement should be resolved at compile time (it being an error if the statement is not resolved). So your example would become: struct BinaryTree<$T> { T data; compileTime if ($T != int) { int key; } Tree left; Tree right; }; struct BinaryTree<$T> { T data; if( resolve( $T != int ) ) { int key; } Tree left; Tree right; }; (actual keywords used are debateable) as mandating constant folding. C 2002/5/26
Jun 26 2002
Whichever is easiest to implement and give us the functionality we need. I'm not stuck on any particular keyword here. In this case, we could just use the if keyword. Since its outside function context, we can assume it will be resolved at compile time. In this case there's really no way for the compiler NOT to resolve this conditional at compile time, unless we are dealing with an interpreted or JITed language. This kind of conditional would sure help me with the C++ templates that I am maintaining right now. struct BinaryTree<$T> { T data; if ($T != int) { int key; } Tree left; Tree right; };
Jun 26 2002
cblack01 wrote:Whichever is easiest to implement and give us the functionality we need.And we want something which is simple to type, easy to figure out the meaning of, consistant with the rest of the language and an effective solution - C++ seams to just go for easy to implement and results in impossible to read syntax (though this may be a by product of the committe design process), we know D can do better.I'm not stuck on any particular keyword here. In this case, we could just use the if keyword. Since its outside function context, we can assume it will be resolved at compile time.Probably, and that is what D does implicitly - adding a keyword would make resolving explicit. In your example it would need to be resolved however if we had a similar construct within a function then some keyword would be needed to ensure, for example... int aFunc($T t) { if( $T == MyClass ) { ... do someting ... } else { ... do something else ... } }In this case there's really no way for the compiler NOT to resolve this conditional at compile time, unless we are dealing with an interpreted or JITed language.Or if the types compared are classes - then RTTI could come into play, which is not what we want in the above example.This kind of conditional would sure help me with the C++ templates that I am maintaining right now.Yes, though D version statements may be used to achieve a similar effect. C 2002/6/26
Jun 26 2002
"Patrick Down" <pat codemoon.com> wrote in message news:Xns92385BBDDAE20patcodemooncom 63.105.9.61... <SNIP>I have a rather crazy idea. What if we treated "type" as a type? type IntType = int; IntType b = 3; One of the things you could do with this is create functions that dealt with types. Here is a function that builds a binary tree type. type BinaryTree(type T) { struct Tree { T data; Tree left; Tree right; }; return Tree; }<SNIP>I like this idea! And it is not as crazy as you may think. In fact I am pretty sure something like this is already in Delphi. I think there it only works for class types, however...Maybe Pavel can give us some more insight to this, I think that he knows Delphi pretty well. -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net _________________________________________________ Remove _XYZ from my address when replying by mail
Jun 26 2002
On Wed, 26 Jun 2002 15:27:45 +0200 "OddesE" <OddesE_XYZ hotmail.com> wrote:I like this idea! And it is not as crazy as you may think. In fact I am pretty sure something like this is already in Delphi. I think there it only works for class types, however...Maybe Pavel can give us some more insight to this, I think that he knows Delphi pretty well.Well, I wouldn't say I know it very well, but I don't remember anything like this in Delphi.
Jun 26 2002
Ada has a type type, if memory serves, so does ecmsScript 2.0 (not a proper standard jet, but it's in development). I think the type type is an elegant solution that fits in with the rest of D, much better than C++ style templates do... The other solution I can imagine fitting in with D syntactically, is to have a type that is a supertype of the primitives, structs etc, and objects, a bit like a void* but without being a pointer. To my mind however, it seems overly complicated. -- Alix Pexton... Webmaster, The D Journal web: www.thedjournal.com email:webmaster thedjournal.com "The D journal, a work in progress..." OddesE <OddesE_XYZ hotmail.com> wrote in article <afcenf$1bka$1 digitaldaemon.com>..."Patrick Down" <pat codemoon.com> wrote in message news:Xns92385BBDDAE20patcodemooncom 63.105.9.61... <SNIP>I have a rather crazy idea. What if we treated "type" as a type?<SNIP>I like this idea! And it is not as crazy as you may think. In fact I am pretty sure something like this is already in Delphi. I think there it only works for class types, however...Maybe Pavel can give us some more insight to this, I think that he knows Delphi pretty well.
Jun 26 2002
"Alix Pexton" <Alix seven-point-star.co.uk> wrote in news:01c21d38$e8680360$96497ad5 jpswm:Ada has a type type, if memory serves, so does ecmsScript 2.0 (not a proper standard jet, but it's in development). I think the type type is an elegant solution that fits in with the rest of D, much better than C++ style templates do... The other solution I can imagine fitting in with D syntactically, is to have a type that is a supertype of the primitives, structs etc, and objects, a bit like a void* but without being a pointer. To my mind however, it seems overly complicated.If you look in the D libary right now you will see that there is ( if I remember correctly ) a ClassInfo and a TypeInfo structure. ClassInfo describes user defined classes. TypeInfo is used more internally to hold certain functions related to basic types and to help implement dynamic arrays and such. It would seem that perhaps these two could be unified to make a standard type descriptor for all types, basic and user defined.
Jun 26 2002
On Wed, 26 Jun 2002 18:10:29 +0000 (UTC) Patrick Down <pat codemoon.com> wrote:If you look in the D libary right now you will see that there is ( if I remember correctly ) a ClassInfo and a TypeInfo structure. ClassInfo describes user defined classes. TypeInfo is used more internally to hold certain functions related to basic types and to help implement dynamic arrays and such. It would seem that perhaps these two could be unified to make a standard type descriptor for all types, basic and user defined.However, it's a run-time solution, as opposed to compile-time (and thus fast and easy to optimize) templates. Personally, I'd prefer to have both, but if I had to choose, I'd better have templates, because they allow to create a set of _fast_, mostly inline classes, encapsulating common algorithms (like STL).
Jun 27 2002
Pavel Minayev <evilone omen.ru> wrote in news:CFN374344668740509 news.digitalmars.com:On Wed, 26 Jun 2002 18:10:29 +0000 (UTC) Patrick Down <pat codemoon.com> wrote:I agree. I think what I've suggested in earlier posts could be a compile time solution. The suggestion I made above about ClassInfo and TypeInfo is a runtime solution but I think the runtime use of a "type" type is for reflection and RTTI. Most "type" expressions would be constant expressions. They could be folded at compile time to concrete types. All variable, parameter, and structure declarations must be reduced to a concrete type by the compiler or it's an error. The main problem with my syntax is that type functions have a similar syntax to normal functions. This makes it hard for the user and the compiler to tell the difference between the two. As suggested elsewhere this is probably a better syntax although I think we should find some other delimiters than < and >. Why not ()? struct SquareMatrix(type T,int size) { T[size][size] data; Matrix(T,size) Multipy(Matrix(T,size)) { } } Design by contract would be nice for this too. struct SquareMatrix(type T,int size) in { assert(isNumericType(T)); } body { T[size][size] data; Matrix(T,size) Multipy(Matrix(T,size) m) { } } However we want isNumericType to be a compile time function. Seems like this is getting back to having a macro language again.If you look in the D libary right now you will see that there is ( if I remember correctly ) a ClassInfo and a TypeInfo structure. ClassInfo describes user defined classes. TypeInfo is used more internally to hold certain functions related to basic types and to help implement dynamic arrays and such. It would seem that perhaps these two could be unified to make a standard type descriptor for all types, basic and user defined.However, it's a run-time solution, as opposed to compile-time (and thus fast and easy to optimize) templates. Personally, I'd prefer to have both, but if I had to choose, I'd better have templates, because they allow to create a set of _fast_, mostly inline classes, encapsulating common algorithms (like STL).
Jun 27 2002
On Thu, 27 Jun 2002 12:21:19 +0000 (UTC) Patrick Down <pat codemoon.com> wrote:However we want isNumericType to be a compile time function. Seems like this is getting back to having a macro language again.It could be a property .isnumeric
Jun 27 2002
As suggested elsewhere this is probably a better syntax although I think we should find some other delimiters than < and >. Why not ()?I think the purpose of not using parens for templates in C++ was so that you (and the compiler) would not confuse template parameters with constructor parameters. Parens are used for a lot of things and if we use them for everything, the syntax can get confusing.
Jun 27 2002
"Craig Black" <cblack ara.com> wrote in message news:aff948$1joc$1 digitaldaemon.com...youAs suggested elsewhere this is probably a better syntax although I think we should find some other delimiters than < and >. Why not ()?I think the purpose of not using parens for templates in C++ was so that(and the compiler) would not confuse template parameters with constructor parameters. Parens are used for a lot of things and if we use them for everything, the syntax can get confusing.Just to expound on this, let's say we have a class A, that has a constructor that takes an integer. Class A is also a template class which takes an integral template parameter. I don't know if D supports the same, but in C++ you can create an temporary instance of this class using the syntax A(n). Do you see the problem? I suppose the compiler could assume that the first set of parens refers to the template, and the second to the constructor. I guess this is just a matter of personal preference. A(n)(n) or A<n>(n)? Then again, D might not even allow the creation of temporaries this way. I dunno.
Jun 27 2002
On Thu, 27 Jun 2002 10:21:12 -0500 "Craig Black" <cblack ara.com> wrote:matter of personal preference. A(n)(n) or A<n>(n)? Then again, D might not even allow the creation of temporaries this way. I dunno.It doesn't. You always have to use operator new to create an object. There is no such thing as "temporary" in D.
Jun 27 2002
"Craig Black" <cblack ara.com> wrote in message news:affa1j$1qdt$1 digitaldaemon.com...I suppose the compiler could assume that the first set of parens refers to the template, and the second to the constructor.Actually, if the name references a template class, using the first set of parens as constructor parameters wouldn't be an option, anyway. The problem would still exist with template functions, though. I see no harm in using something unambiguous and visible, like [[...]]: struct Array[[type T, int size]] { T theArray[size]; }; generic[[type T]] T Min(T v0, T v1); Salutaciones, JCAB
Jun 27 2002
"Craig Black" <cblack ara.com> wrote in news:aff948$1joc$1 digitaldaemon.com:Yes but they caused an equall number of problems in C++ with the >> operator.As suggested elsewhere this is probably a better syntax although I think we should find some other delimiters than < and >. Why not ()?I think the purpose of not using parens for templates in C++ was so that you (and the compiler) would not confuse template parameters with constructor parameters. Parens are used for a lot of things and if we use them for everything, the syntax can get confusing.
Jun 27 2002
On Thu=2C 27 Jun 2002 16=3A15=3A56 +0000 =28UTC=29 Patrick Down =3Cpat=40codemoon=2Ecom=3E wrote=3A =3E Yes but they caused an equall number of problems in C++ with the =3E=3E =3E operator=2E Well=2C then=2C use something else =3D=29 Maybe backticks=3F =09template `type T` class tree { =2E=2E=2E } =09template `type T` class deque { =2E=2E=2E } =09tree`deque`int`` foo=3B
Jun 27 2002
Hello, way to represet variable parameters using the params keyword. It works something like this. void print(params string [] strings) { ... } print("Any", "number", "of", "parameters"); Brace yourselves. This is a very advanced idea. But I encourage you to stretch your mind and think outside of the box. We could extend this variable parameter concept to templates. Observe. class Tuple<params type $types[]> { // We would have to provide some syntax to extract each type // outside of function syntax. The following is very sketchy. foreach (type T in $types) { } }; I know it looks bad. It's kinda like a C preprocessor macro combined with a suggestions as to how to best express this. Perhaps the "type" type approach suggested earlier. What is required is a syntax for conditional structure building. With the above generic you could have multiple return values: Tuple<int, float> func(); In C++ you would have to define a template for each number of parameters supported e.g. Tuple2, Tuple3, Tuple4, Tuple5, etc. But shouldn't we be able to define one template that can handle any number of parameters? --Craig
Jul 02 2002
"Patrick Down" <pat codemoon.com> wrote in message news:Xns923986BCD9ED7patcodemooncom 63.105.9.61...If you look in the D libary right now you will see that there is ( if I remember correctly ) a ClassInfo and a TypeInfo structure. ClassInfo describes user defined classes. TypeInfo is used more internally to hold certain functions related to basic types and to help implement dynamic arrays and such. It would seem that perhaps these two could be unified to make a standard type descriptor for all types, basic and user defined.TypeInfo certainly has promise for a more general type descriptor functionality.
Jul 10 2002
void // only property is that it's a type, although you can't do *anything* with it! | +---scalar | | | +---integral | symbolic | real | enumeration +---aggregate | | | +---struct | class | union | +---pointer | +---array | +---fixedarray dynarray Something like that. I could really go for a "unknown type" keyword, but when there's more than one you have to say which unknown type you mean. And all usages have to agree. Sean "Alix Pexton" <Alix seven-point-star.co.uk> wrote in message news:01c21d38$e8680360$96497ad5 jpswm...Ada has a type type, if memory serves, so does ecmsScript 2.0 (not aproperstandard jet, but it's in development). I think the type type is an elegant solution that fits in with the rest of D, much better than C++ style templates do... The other solution I can imagine fitting in with D syntactically, is to have a type that is a supertype of the primitives, structs etc, and objects, a bit like a void* but without being a pointer. To my mind however, it seems overly complicated. -- Alix Pexton... Webmaster, The D Journal web: www.thedjournal.com email:webmaster thedjournal.com "The D journal, a work in progress..." OddesE <OddesE_XYZ hotmail.com> wrote in article <afcenf$1bka$1 digitaldaemon.com>..."Patrick Down" <pat codemoon.com> wrote in message news:Xns92385BBDDAE20patcodemooncom 63.105.9.61... <SNIP>I have a rather crazy idea. What if we treated "type" as a type?<SNIP>I like this idea! And it is not as crazy as you may think. In fact I am pretty sure something like this is already in Delphi. I think there it only works for class types, however...Maybe Pavel can give us some more insight to this, I think that he knows Delphi pretty well.
Jun 27 2002
I suggested something similar to this in the thread 'Type categories and inheritance' ab925u$20bq$1 digitaldaemon.com It looked like this: +-- Variable +-- void +-- Boolean | +-- bit | +-- Character | +-- char | +-- wchar | +-- Number | +-- imaginary | +-- complex | +-- Real | | +-- float | | +-- double | | +-- extended | | | +-- Integral | +-- Signed | | +-- byte | | +-- short | | +-- int | | +-- long | | +-- cent | | | +-- Unsigned | +-- ubyte | +-- ushort | +-- uint | +-- ulong | +-- ucent | +-- Pointer | +-- void * | +-- char * | +-- etc, etc... | +-- Delegate | +-- FunctionPointer | +-- Array | +-- Struct | +-- Structs... | +-- Class | +-- Object | +-- Loads | +-- Of | +-- Classes... | +-- Interface +-- IUnknown | +-- COM Interfaces... | +-- Other Interfaces... it can convert any basic type to an Object, so you can call methods on it: int i = 10; print (i.toString()); It even works with literals!: print (10.toString()); To me this seems like a really awesome feature, allowing you to easily write functions that accept parameters of all types. -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net _________________________________________________ Remove _XYZ from my address when replying by mail
Jun 27 2002
You'll have to wait a few days for Walters return. He informs us that he is working on templates at this very moment. Well probably only in his subconscious at present because he's on holidays. We'll probably have to wait and see what he comes up with. I'd be a good idea to get any good ideas into the design though.
Jun 25 2002
"Craig Black" <cblack ara.com> wrote in message news:af7k2g$1f31$1 digitaldaemon.com...First of all, I would like to say that I like the direction that D isgoingso far, and appreciate your innovative work on this new language.Thanks!I know support for generics in D is probably still on the horizin, buthaveyou given it any serious thought? We can definitely improve on C++ templates, both in ease of implementation and flexibility. Even beforeyoustart on templates it would be good to have in mind at least a vagueconceptof what you plan to do. I use C++ templates aggressively, so I have some ideas about features to add and drop.What I'm doing right now is finishing template support in the C++ compiler. That gives me a credible foundation to do a better job in D.First, if you haven't read Modern C++ Design: Generic Programming andDesignPatterns Applied by Andrei Alexandrescu, you should get a copy. A great book! I have already applied many of the concepts he covers. It shouldberequired reading for anyone who wants in depth understand of Generic Programming.Ok, I'll check it out. Though if it advocates the STL design, I'm afraid I'm skeptical.I have so many ideas and could write forever about generics, here's just some food for thought. If you're interested, I would be glad to sharemoreideas.Fire away!I will just give you a few insights of where you can improve on C++.First,we generic programmers need a compile-time typeof operator. I have runintoso many cases where I said to myself, "I sure wish I had a typeofoperator."It would make generic programming so much more elegant. Then you couldhavecompile-time conditionals to handle different types in different ways,likethis: cswitch(typeof(variable)) { case int: // handle an integer case string: // hangle a string ... } Here "cswitch" is a compile-time conditional. This means the conditionalisresolved at compile time, and optimized appropriately so that noperformanceis lost and dead code is eliminated. You could also have cif, celse, etc.Ok, that's a good idea.Another idea I have to improve on C++ is type specialization syntax. We could implement type specialization more explicitly using typelists. This would provide a more readable type specialization that (I think) would be easier to implement. Here's a simple example: template <typename T : {int, uint, long, ulong, float, double}> T Add(T a, T b) { return a + b; } This specializes the Add function to need apply only to int, float,double,and extended. You could then write another Add template that would handle concatenation of container types.I have some ideas on type specialization, the syntax for C++ is terrible (and trust me, it's really hard to write a compiler for!).This leads me to another feature that would be nice to have: type lists(seechapter 3 of Modern C++ design.) It would be nice to categorize types something like this: typelist NumericTypes { int, uint, long, ulong, float, double }; typelist ContainerTypes { list, set, vector, queue, stack }; Then you could rewrite the Add function: template <typename T : NumericTypes> T Add(T a, T b) { return a + b; } template <typename T : ContainerTypes> T Add(T a, T b) { T result; result.append(a); result.append(b); return result; }Ok, that's another good idea.
Jul 03 2002