June 27, 2002 Re: Generics in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to cblack01 | 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. >>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. 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, 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. >>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? 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. |
June 27, 2002 Re: Generics in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Alix Pexton | 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 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. > |
June 27, 2002 Re: Generics in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Pavel Minayev | 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: > >> 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). 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. |
June 27, 2002 Re: Generics in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Patrick Down | 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
|
June 27, 2002 Re: Generics in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Patrick Down | > 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.
|
June 27, 2002 Re: Generics in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Craig Black | "Craig Black" <cblack@ara.com> wrote in message news:aff948$1joc$1@digitaldaemon.com... > > 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. 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. |
June 27, 2002 Burton is great | ||||
---|---|---|---|---|
| ||||
Posted in reply to Burton Radons | This is good stuff. --Craig "Burton Radons" <loth@users.sourceforge.net> wrote in message news:3D1AD1CD.3080308@users.sourceforge.net... > 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. > > >>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. > > > 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, 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. > > >>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? > > > 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. > |
June 27, 2002 Re: Generics in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Craig Black | "Craig Black" <cblack@ara.com> wrote in news:aff948$1joc$1@digitaldaemon.com: >> 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. > > > Yes but they caused an equall number of problems in C++ with the >> operator. |
June 27, 2002 Re: Generics in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Burton Radons | 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 |
June 27, 2002 Re: Generics in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean L. Palmer | 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... Later I learned that C# has a feature where 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 |
Copyright © 1999-2021 by the D Language Foundation