digitalmars.D.learn - Am I getting this all right?
- Jason House (40/40) Dec 13 2006 I'm kind of doing a trial by fire method to learn D and how it works... ...
- Sean Kelly (39/81) Dec 13 2006 Check DSource (www.dsource.org). IIRC there is at least one STL
- Ary Manzana (39/50) Dec 13 2006 It worked for me, if T is a class. If it's a primitive type, you should
- Jason House (23/79) Dec 13 2006 When poking around that site, I didn't see anything obviously STL
- Chris Nicholson-Sauls (100/161) Dec 13 2006 There is a branch of the Mango tree for containers.
- Sean Kelly (4/9) Dec 13 2006 I've got a module of array ops that offers heap and set operations, as
- Jason House (5/5) Dec 14 2006 An earlier post showed stack with push and pop for an array. How does o...
- Chris Nicholson-Sauls (35/42) Dec 14 2006 Well... I don't know that I've ever done Queue/Set, but it wouldn't be h...
- Sean Kelly (33/38) Dec 14 2006 A queue isn't easy because array-based queues generally need to track
- Jarrett Billingsley (58/61) Dec 14 2006 You could also use an associative array to model a set.
- Bill Baxter (13/37) Dec 14 2006 That's the right way to go. Using arrays for sets is going to be
- Jarrett Billingsley (9/18) Dec 14 2006 That prints "true true true". :)
- Jarrett Billingsley (3/9) Dec 14 2006 Whoops, nevermind, that's right. I missed the .keys.
- Bill Baxter (8/31) Dec 14 2006 Hmm. Ok, so you really do want to use foreach(...; set) if at all possi...
- Jarrett Billingsley (9/15) Dec 14 2006 Meh, I don't think the
- Bill Baxter (8/30) Dec 14 2006 I guess not. Might be interesting if AA's allowed a void value type.
- Jarrett Billingsley (11/17) Dec 14 2006 Actually, they used to, and people used them as sets :) Of course, that...
- Sean Kelly (6/9) Dec 14 2006 I think the design was pretty well settled when things ended. The next
- Bill Baxter (3/12) Dec 14 2006 Huh. So what is your understanding of what the consensus was?
- Sean Kelly (6/18) Dec 15 2006 Java-style, with random access iterators overloading array operations.
- Bill Baxter (6/23) Dec 15 2006 I like next/value/(ptr) myself.
- Sean Kelly (7/33) Dec 15 2006 It's great for loops, but can be confusing when iterators stick around
- Bill Baxter (13/56) Dec 15 2006 Good point. There's another problem related to iters sitting around a
- Oskar Linde (78/138) Dec 15 2006 Yes, this may be better. This was basically the point the last iterator
- Sean Kelly (28/99) Dec 27 2006 Not necessarily. The dummy node could be shared by both. This is one
- Sean Kelly (9/19) Dec 13 2006 This actually works for arrays, but only arrays. People have asked in
- Bill Baxter (53/88) Dec 13 2006 Never tried either one, so can't help you there.
I'm kind of doing a trial by fire method to learn D and how it works... I'm taking an existing open source project and converting it over. Here's the stuff that I've found / questions that I have. Thanks in advance for all the thoughtful responses. I know this is a long post! I've worked through the issues to get working code, but I think my issues will be hit by others. It seems that DTL and minTL are the two candidates for an STL equivalent in D. Both seem to be out of date. Since minTL is documented, I chose to use that. I found that the latest dmd (0.176) doesn't compile the latest minTL. It complains that va_arg isn't defined even though it imports std.stdarg. Adding a fully qualified name fixed my usage problem. Is this really the best option that I have for STL equivalent? Anyone else compiling this stuff and hitting problems? I know of no way in d to provide a const qualifier. It seems like the concept purely doesn't exist. minTL appears to have a workaround where it templates itself on a boolean value, and simply doesn't publish certain functions. When will a real const qualifier get added to the language? It seems really strange that a language that adds all kinds of contract programming wouldn't use const qualifiers / const types. After banging my head on printing stuff for a long time, I've come to a few conclusions: * The C++ equivalent to std::ostream& operator << (std::ostream &out, const type &x) does not exist * Custom types use the toString property * Enums do not (and can not) have a toString property * I have found no way to determine (in a templated class) if a type is printable or not. static if(is(typeof(T))) comes close, but my very first test using ints failed. The special unittest member function doesn't get built in with -unittest unless the actual class is used in some way (and then one copy of the unittest funciton gets run for each type). I'd really like to see some way for this to work. for example, class foo(T){ ... unittest{ foo!(int) sample; ...} } does not run unless other code instantiates foo!(U) In my early efforts at doing operator overloading, I wrote opCmp and then was shocked when my unit test showed that == didn't even call opCmp. It silently did something wrong. This seems like a gotcha built into the language that should probably get remedied. I couldn't find a way to reinitialize a variable back to a default value... For example class foo(T){ T[] bar; void func(){bar[3] = new T();} } won't compile. I'm not too sure why this is the case.
Dec 13 2006
Jason House wrote:I'm kind of doing a trial by fire method to learn D and how it works... I'm taking an existing open source project and converting it over. Here's the stuff that I've found / questions that I have. Thanks in advance for all the thoughtful responses. I know this is a long post! I've worked through the issues to get working code, but I think my issues will be hit by others. It seems that DTL and minTL are the two candidates for an STL equivalent in D. Both seem to be out of date. Since minTL is documented, I chose to use that. I found that the latest dmd (0.176) doesn't compile the latest minTL. It complains that va_arg isn't defined even though it imports std.stdarg. Adding a fully qualified name fixed my usage problem. Is this really the best option that I have for STL equivalent? Anyone else compiling this stuff and hitting problems?Check DSource (www.dsource.org). IIRC there is at least one STL replacement project there. Of the above, DTL was created by Matthew Wilson, and hasn't been updated in at least a year. MinTL was created by Ben Hinkle, and has been dormant for almost as long. MinTL is more mature however, and should be easier to update.I know of no way in d to provide a const qualifier. It seems like the concept purely doesn't exist. minTL appears to have a workaround where it templates itself on a boolean value, and simply doesn't publish certain functions. When will a real const qualifier get added to the language? It seems really strange that a language that adds all kinds of contract programming wouldn't use const qualifiers / const types.This is correct. In D, 'const' is a storage class, and can not be applied to values at runtime (essentially). D has no run-time const behavior largely because the implementations in expisting popular languages are undesirable (C++ const, for example) for various reasons, and some of the more radical solutions such as const-by-default came up too late in the language's development cycle (as I understand it).After banging my head on printing stuff for a long time, I've come to a few conclusions: * The C++ equivalent to std::ostream& operator << (std::ostream &out, const type &x) does not existIt could. Mango (available on DSource) overloaded these operators for a while, but no one used them and I think they may have been removed. Mango's "whisper syntax" seems preferable in most cases, though it doesn't work for an IOStream concept, while the shift operators do.* Custom types use the toString propertyYes, though some of us wish this function were called "toUtf8" to improve clarity. This is an idealistic point however, and not pertinent to the discussion.* Enums do not (and can not) have a toString propertyThey don't at the moment. One could be added, I imagine, but it would have to be done in the compiler.* I have found no way to determine (in a templated class) if a type is printable or not. static if(is(typeof(T))) comes close, but my very first test using ints failed."static if(is(typeof(T.toString)))" should tell you whether the function is defined, if T is a struct or class, but it sounds like you want to test concrete types as well?The special unittest member function doesn't get built in with -unittest unless the actual class is used in some way (and then one copy of the unittest funciton gets run for each type). I'd really like to see some way for this to work. for example, class foo(T){ ... unittest{ foo!(int) sample; ...} } does not run unless other code instantiates foo!(U)Why not do: class C(T) {} unittest { /* test C here */ } Since private data is actually visible at module scope, the above approach loses nothing over having unittest within the class definition itself.In my early efforts at doing operator overloading, I wrote opCmp and then was shocked when my unit test showed that == didn't even call opCmp. It silently did something wrong. This seems like a gotcha built into the language that should probably get remedied.It calls opEquals. Personally, I prefer this approach as it's not uncommon for me to define an ordering scheme that is less strict than I want for equality comparisons.I couldn't find a way to reinitialize a variable back to a default value... For example class foo(T){ T[] bar; void func(){bar[3] = new T();} } won't compile. I'm not too sure why this is the case.Try: T[] bar = new T[size]; T[0 .. $] = new T(); You still have to resize and assign in separate operations, but the above should work. Sean
Dec 13 2006
Sean Kelly escribió:Jason House wrote:It worked for me, if T is a class. If it's a primitive type, you should do "T.init" instead of "new T()". So heres the code: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv class foo(T) { T[] bar; void func(){ static if (is(T == class)) { bar[3] = new T(); // TODO: what if it's a struct, typedef, etc.? } else { bar[3] = T.init; } } } ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ BTW, I could compile this: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv class foo(T) { } void main() { mixin foo!(int) a; } ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ but this gives me an error vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 1. class foo(T) { 2. 3. } 4. 5. void main() { 6. mixin foo!(int) a; 7. mixin foo!(real) b; 8. } ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^I couldn't find a way to reinitialize a variable back to a default value... For example class foo(T){ T[] bar; void func(){bar[3] = new T();} } won't compile. I'm not too sure why this is the case.Try: T[] bar = new T[size]; T[0 .. $] = new T();main.d(7): mixin foo!(real) foo is not a templateWhy?
Dec 13 2006
Sean Kelly wrote:Check DSource (www.dsource.org). IIRC there is at least one STL replacement project there. Of the above, DTL was created by Matthew Wilson, and hasn't been updated in at least a year. MinTL was created by Ben Hinkle, and has been dormant for almost as long. MinTL is more mature however, and should be easier to update.When poking around that site, I didn't see anything obviously STL related. I've been known to be bline in the past.That's exactly correct... Or at the very least the compiler must allow such properties to be added to them. I did try adding my own toString property (just in case there was neat hidden feature like that)* Custom types use the toString propertyYes, though some of us wish this function were called "toUtf8" to improve clarity. This is an idealistic point however, and not pertinent to the discussion.* Enums do not (and can not) have a toString propertyThey don't at the moment. One could be added, I imagine, but it would have to be done in the compiler.Sorry, typo in my original post. What you propose is what I put in the code. Yes, I want to handle concrete types as well.* I have found no way to determine (in a templated class) if a type is printable or not. static if(is(typeof(T))) comes close, but my very first test using ints failed."static if(is(typeof(T.toString)))" should tell you whether the function is defined, if T is a struct or class, but it sounds like you want to test concrete types as well?Why not do: class C(T) {} unittest { /* test C here */ } Since private data is actually visible at module scope, the above approach loses nothing over having unittest within the class definition itself.That's what I have to do, but it seems to be against "the D way" of embedding contracts and unit tests as closely as possible to the true code. I haven't used ddoc, but I bet the alternate method may yield misleading documentation.I can totally see that. But what happens when only opCmp is defined? Should the default opEquals use opCmp or do something else? I was assuming it'd use opCmp. Again, in what I perceive to be the style of D, such oops type things should possibly cause a warning.In my early efforts at doing operator overloading, I wrote opCmp and then was shocked when my unit test showed that == didn't even call opCmp. It silently did something wrong. This seems like a gotcha built into the language that should probably get remedied.It calls opEquals. Personally, I prefer this approach as it's not uncommon for me to define an ordering scheme that is less strict than I want for equality comparisons.I'll try that. My actual code was essentially T[] bar = new T[size]; for (int i=0; i<size; i++) T[i] = new T(); ... which I totally expect to work. (sorry for leaving out the array sizing in my original example)I couldn't find a way to reinitialize a variable back to a default value... For example class foo(T){ T[] bar; void func(){bar[3] = new T();} } won't compile. I'm not too sure why this is the case.Try: T[] bar = new T[size]; T[0 .. $] = new T(); You still have to resize and assign in separate operations, but the above should work.
Dec 13 2006
Jason House wrote:Sean Kelly wrote:There is a branch of the Mango tree for containers. http://dsource.org/projects/mango That said, I find that I rarely miss container classes/structs in D. The most common cases are handled by variable-length arrays. (Although I do have pseudo-member functions in Cashew for simulating a stack using an array.) http://dsource.org/projects/cashew Trees are also very easily achieved in D. If all you need is the basic concept of a tree structure, with breadth-first and depth-first iteration, its a snap. Something like this, for example: array."); (Of course there are some things that just seem to work better with elaborate container libraries. Its all according to the needs, as with anything.)Check DSource (www.dsource.org). IIRC there is at least one STL replacement project there. Of the above, DTL was created by Matthew Wilson, and hasn't been updated in at least a year. MinTL was created by Ben Hinkle, and has been dormant for almost as long. MinTL is more mature however, and should be easier to update.When poking around that site, I didn't see anything obviously STL related. I've been known to be bline in the past.No... but you can have a constant associative array, with the enum as the key and a string as the value. This is what I usually do when I want string representations of enum values. For a cheap example:That's exactly correct... Or at the very least the compiler must allow such properties to be added to them. I did try adding my own toString property (just in case there was neat hidden feature like that)* Enums do not (and can not) have a toString propertyThey don't at the moment. One could be added, I imagine, but it would have to be done in the compiler.That's what I have to do, but it seems to be against "the D way" of embedding contracts and unit tests as closely as possible to the true code. I haven't used ddoc, but I bet the alternate method may yield misleading documentation.So far as I have personally experienced, DDoc doesn't emit any content for unittests anyhow. So there should be no impact as far as that goes. And since you can have as many unittests in a module as you like, its still pretty "D like" to have a unittest block after each class definition.I for one think the default opEquals probably /should/ use opCmp... but alas.I can totally see that. But what happens when only opCmp is defined? Should the default opEquals use opCmp or do something else? I was assuming it'd use opCmp. Again, in what I perceive to be the style of D, such oops type things should possibly cause a warning.In my early efforts at doing operator overloading, I wrote opCmp and then was shocked when my unit test showed that == didn't even call opCmp. It silently did something wrong. This seems like a gotcha built into the language that should probably get remedied.It calls opEquals. Personally, I prefer this approach as it's not uncommon for me to define an ordering scheme that is less strict than I want for equality comparisons.You can also use... bar[] = new T; ...to emulate the above. If I recall right, array[] as an LValue is the same as array[0..$] as one. However, chances are what you meant to do was to set each element to a /seperate/ object, rather than setting them all to the same one... If so, the following is what you would probably rather do. Above all, have fun with your new D experience. :) -- Chris Nicholson-SaulsI'll try that. My actual code was essentially T[] bar = new T[size]; for (int i=0; i<size; i++) T[i] = new T(); ... which I totally expect to work. (sorry for leaving out the array sizing in my original example)I couldn't find a way to reinitialize a variable back to a default value... For example class foo(T){ T[] bar; void func(){bar[3] = new T();} } won't compile. I'm not too sure why this is the case.Try: T[] bar = new T[size]; T[0 .. $] = new T(); You still have to resize and assign in separate operations, but the above should work.
Dec 13 2006
Chris Nicholson-Sauls wrote:That said, I find that I rarely miss container classes/structs in D. The most common cases are handled by variable-length arrays. (Although I do have pseudo-member functions in Cashew for simulating a stack using an array.)I've got a module of array ops that offers heap and set operations, as well as sort, binary search, etc. And I feel quite the same. Sean
Dec 13 2006
An earlier post showed stack with push and pop for an array. How does one do a queue? a set? Also, I haven't found a way to check if something is in an associative array or not. This may all boil down to me not being able to find a comprehensive list of array properties and/or quality documentation on the D language.
Dec 14 2006
Jason House wrote:An earlier post showed stack with push and pop for an array. How does one do a queue? a set? Also, I haven't found a way to check if something is in an associative array or not. This may all boil down to me not being able to find a comprehensive list of array properties and/or quality documentation on the D language.Well... I don't know that I've ever done Queue/Set, but it wouldn't be hard. Quick cheap version of a Queue off the top of my head: Or if one is using Cashew, you could really just do: As for a Set... well, that might take a class/struct wrapper to do succinctly. Or, again using cashew, you could just make a point of calling .unique() after each insert/concat. Not very pretty though. -- Chris Nicholson-Sauls
Dec 14 2006
Jason House wrote:An earlier post showed stack with push and pop for an array. How does one do a queue? a set?A queue isn't easy because array-based queues generally need to track where the head of the queue is (that or move the rest of the queue on each pop operation), so queues really need an object wrapper to be done well. However, storing the data in an array is still generally faster than using a linked list. I ran a test not too long ago in Java, and an array-based queue was roughly 50% faster than a linked list-based queue for inserting and removing one million elements, and that was using a 'for' loop to copy elements during a resize operation (instead of a memcpy). A free-list could improve average performance of a linked list implementation, but in a worst case scenario the array-based queue will still win (assuming a non-trivial allocation cost). Sets are easily modeled as sorted arrays however. But the real advantage of offering these algorithms apart from any specific container is that they can be applied to any sequence that supports the appropriate operations. For example, the set intersection operation could be applied to two SQL result sets as easily as to arrays, and no copying to a Set container would be necessary. My code currently only supports arrays, but that is mostly because there is no accepted iterator definition for D. But this topic was discussed pretty heavily about a month ago and I may go ahead and just create one. It's just lingering a bit low on my to-do list at the moment.Also, I haven't found a way to check if something is in an associative array or not.if( x in myAA ) {} The 'in' operator actually returns a pointer to the value, or null if the value is not present, so a test and modify operation might do: if( auto t = x in myAA ) *t = u;This may all boil down to me not being able to find a comprehensive list of array properties and/or quality documentation on the D language.The array documentation is actually some of the best in the spec. "in" is mentioned in the Associative Array section: http://www.digitalmars.com/d/arrays.html#associative But is also documented as an expression: http://www.digitalmars.com/d/expression.html#InExpression Sean
Dec 14 2006
"Jason House" <jhouse mitre.org> wrote in message news:elsctg$5ca$1 digitaldaemon.com...An earlier post showed stack with push and pop for an array. How does one do a queue? a set?You could also use an associative array to model a set. bool[int] set; set[4] = true; set[6] = true; set[10] = true; if(4 in set) writefln("4 is in the set"); foreach(v, nothing; set) writefln(v); set.remove(6); The "nothing" in the foreach loop is because the values in the associative array are useless -- they're just there because they have to be. In fact, why don't I just make a little set class to make it a little prettier. class Set(T) { protected bool[T] mData; public this() { } public void add(T value) { mData[value] = true; } public bool opIn_r(T value) { return ((value in mData) !is null); } public int opApply(int delegate(inout T value) dg) { int result = 0; foreach(value, n; mData) { result = dg(value); if(result) break; } return result; } public void remove(T value) { mData.remove(value); } } void main() { auto scope set = new Set!(int); set.add(4); set.add(6); set.add(10); if(4 in set) writefln("4 is in the set"); foreach(v; set) writefln(v); set.remove(6); }
Dec 14 2006
Jarrett Billingsley wrote:"Jason House" <jhouse mitre.org> wrote in message news:elsctg$5ca$1 digitaldaemon.com...That's the right way to go. Using arrays for sets is going to be sllloooooow.An earlier post showed stack with push and pop for an array. How does one do a queue? a set?You could also use an associative array to model a set.bool[int] set; set[4] = true; set[6] = true; set[10] = true; if(4 in set) writefln("4 is in the set"); foreach(v, nothing; set) writefln(v);Or just use foreach(v; set.keys) writefln(v);set.remove(6); The "nothing" in the foreach loop is because the values in the associative array are useless -- they're just there because they have to be. In fact, why don't I just make a little set class to make it a little prettier.The only reason not would be because opApply is slower than the builtin foreach on an array. At least for regular arrays. Not sure if the same is true for AA's. Also does anyone know if .keys and .values are O(1) operations? Or do they have to allocate a new array and copy keys/values? That could be an important thing to know. Should be part of the spec, I think. --bb
Dec 14 2006
"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:elsr1j$lu0$1 digitaldaemon.com...Or just use foreach(v; set.keys) writefln(v);That prints "true true true". :)The only reason not would be because opApply is slower than the builtin foreach on an array. At least for regular arrays. Not sure if the same is true for AA's.I think it'd be slower for AAs too because in the class opApply function you have to use foreach on the AA that holds the data. But really I guess it's only one method call, so it probably wouldn't be bad at all. After all, custom implementations of opApply work virtually the same way as the built-in ones.Also does anyone know if .keys and .values are O(1) operations? Or do they have to allocate a new array and copy keys/values? That could be an important thing to know. Should be part of the spec, I think.They allocate new arrays. But when you foreach an AA, it doesn't call them.
Dec 14 2006
"Jarrett Billingsley" <kb3ctd2 yahoo.com> wrote in message news:elsu1f$pq5$1 digitaldaemon.com..."Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:elsr1j$lu0$1 digitaldaemon.com...Whoops, nevermind, that's right. I missed the .keys.Or just use foreach(v; set.keys) writefln(v);That prints "true true true". :)
Dec 14 2006
Jarrett Billingsley wrote:"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:elsr1j$lu0$1 digitaldaemon.com...I don't think so. set.values would give you that.Or just use foreach(v; set.keys) writefln(v);That prints "true true true". :)Hmm. Ok, so you really do want to use foreach(...; set) if at all possible. Sure would be nice if there were a .keyiter that could be used with foreach that was efficient and didn't require allocations. Too bad the iterator discussions fizzled out without anything getting decided. --bbThe only reason not would be because opApply is slower than the builtin foreach on an array. At least for regular arrays. Not sure if the same is true for AA's.I think it'd be slower for AAs too because in the class opApply function you have to use foreach on the AA that holds the data. But really I guess it's only one method call, so it probably wouldn't be bad at all. After all, custom implementations of opApply work virtually the same way as the built-in ones.Also does anyone know if .keys and .values are O(1) operations? Or do they have to allocate a new array and copy keys/values? That could be an important thing to know. Should be part of the spec, I think.They allocate new arrays. But when you foreach an AA, it doesn't call them.
Dec 14 2006
"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:elsv06$r2e$1 digitaldaemon.com...Hmm. Ok, so you really do want to use foreach(...; set) if at all possible. Sure would be nice if there were a .keyiter that could be used with foreach that was efficient and didn't require allocations.Meh, I don't think the foreach(key, ____; set) ... Is that bad. Maybe it's a little unclear, but as far as efficiency goes, it's just passing the extra unused value parameter.Too bad the iterator discussions fizzled out without anything getting decided.Yeah. We didn't start a three-week four-hundred-post thread about it, so I guess Walter didn't consider it important.
Dec 14 2006
Jarrett Billingsley wrote:"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:elsv06$r2e$1 digitaldaemon.com...I guess not. Might be interesting if AA's allowed a void value type. void[int] myset; Hmm... maybe not.Hmm. Ok, so you really do want to use foreach(...; set) if at all possible. Sure would be nice if there were a .keyiter that could be used with foreach that was efficient and didn't require allocations.Meh, I don't think the foreach(key, ____; set) ... Is that bad. Maybe it's a little unclear, but as far as efficiency goes, it's just passing the extra unused value parameter.:-) But it was almost that long wasn't it? And Walter was one of the the ones that kicked it off, IIRC. So I had high hopes something would come of it. --bbToo bad the iterator discussions fizzled out without anything getting decided.Yeah. We didn't start a three-week four-hundred-post thread about it, so I guess Walter didn't consider it important.
Dec 14 2006
"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:elsvmo$rsb$1 digitaldaemon.com...I guess not. Might be interesting if AA's allowed a void value type. void[int] myset; Hmm... maybe not.Actually, they used to, and people used them as sets :) Of course, that was also before accessing a nonexistent AA element was an indexing error, so to add something to the set, you did set[4] = set[4]; Which would add 4, or just be a no-op. Now that's just plain illegal, so even if void were allowed as the value type, there'd be no way to add anything to the set. Besides, what does void[int] mean? (then again you can have a void[], which is also kind of weird, but..).:-) But it was almost that long wasn't it? And Walter was one of the the ones that kicked it off, IIRC. So I had high hopes something would come of it.I don't know. Maybe we didn't say the right things.
Dec 14 2006
Bill Baxter wrote:Too bad the iterator discussions fizzled out without anything getting decided.I think the design was pretty well settled when things ended. The next step would be a sample implementation so folks could wrangle over syntax. It's on my "to do" list, but I'm a bit short on free time at the moment. Sean
Dec 14 2006
Sean Kelly wrote:Bill Baxter wrote:Huh. So what is your understanding of what the consensus was? --bbToo bad the iterator discussions fizzled out without anything getting decided.I think the design was pretty well settled when things ended. The next step would be a sample implementation so folks could wrangle over syntax. It's on my "to do" list, but I'm a bit short on free time at the moment.
Dec 14 2006
Bill Baxter wrote:Sean Kelly wrote:Java-style, with random access iterators overloading array operations. I can't remember if there was any clear preference for the hasNext/getNext vs. the atEnd/getVal approach, but I tend to favor the latter. SeanBill Baxter wrote:Huh. So what is your understanding of what the consensus was?Too bad the iterator discussions fizzled out without anything getting decided.I think the design was pretty well settled when things ended. The next step would be a sample implementation so folks could wrangle over syntax. It's on my "to do" list, but I'm a bit short on free time at the moment.
Dec 15 2006
Sean Kelly wrote:Bill Baxter wrote:I like next/value/(ptr) myself. Makes for very succinct while loops. ptr available where it makes sense. while(iter.next()) { writefln(iter.value); } while(iter.next()) { *iter.ptr = 17; } --bbSean Kelly wrote:Java-style, with random access iterators overloading array operations. I can't remember if there was any clear preference for the hasNext/getNext vs. the atEnd/getVal approach, but I tend to favor the latter.Bill Baxter wrote:Huh. So what is your understanding of what the consensus was?Too bad the iterator discussions fizzled out without anything getting decided.I think the design was pretty well settled when things ended. The next step would be a sample implementation so folks could wrangle over syntax. It's on my "to do" list, but I'm a bit short on free time at the moment.
Dec 15 2006
Bill Baxter wrote:Sean Kelly wrote:It's great for loops, but can be confusing when iterators stick around for a while. Say I have some code that operates on the current value of an iterator. With the next() approach, how do I know whether the iterator is valid? Still, perhaps a hybrid approach is best. Have next return true on success and offer an atEnd property as well. SeanBill Baxter wrote:I like next/value/(ptr) myself. Makes for very succinct while loops. ptr available where it makes sense. while(iter.next()) { writefln(iter.value); } while(iter.next()) { *iter.ptr = 17; }Sean Kelly wrote:Java-style, with random access iterators overloading array operations. I can't remember if there was any clear preference for the hasNext/getNext vs. the atEnd/getVal approach, but I tend to favor the latter.Bill Baxter wrote:Huh. So what is your understanding of what the consensus was?Too bad the iterator discussions fizzled out without anything getting decided.I think the design was pretty well settled when things ended. The next step would be a sample implementation so folks could wrangle over syntax. It's on my "to do" list, but I'm a bit short on free time at the moment.
Dec 15 2006
Sean Kelly wrote:Bill Baxter wrote:Good point. There's another problem related to iters sitting around a while, too, that I hadn't considered. If you have to call next() to get the first item then you'll also need some way to query if the iterator is in it's "pre-begin" state. So the next/atend approach only really works when there's no 'value' and 'next' is the only way to get the value. Ick. So maybe a for-ish way is better than while-ish way: for (; !iter.end; iter.next) { writefln(iter.value); } And have iterators start off valid (if not already at the end). --bbSean Kelly wrote:It's great for loops, but can be confusing when iterators stick around for a while. Say I have some code that operates on the current value of an iterator. With the next() approach, how do I know whether the iterator is valid? Still, perhaps a hybrid approach is best. Have next return true on success and offer an atEnd property as well.Bill Baxter wrote:I like next/value/(ptr) myself. Makes for very succinct while loops. ptr available where it makes sense. while(iter.next()) { writefln(iter.value); } while(iter.next()) { *iter.ptr = 17; }Sean Kelly wrote:Java-style, with random access iterators overloading array operations. I can't remember if there was any clear preference for the hasNext/getNext vs. the atEnd/getVal approach, but I tend to favor the latter.Bill Baxter wrote:Huh. So what is your understanding of what the consensus was?Too bad the iterator discussions fizzled out without anything getting decided.I think the design was pretty well settled when things ended. The next step would be a sample implementation so folks could wrangle over syntax. It's on my "to do" list, but I'm a bit short on free time at the moment.
Dec 15 2006
Bill Baxter wrote:Sean Kelly wrote:Yes, this was basically the consensus.Bill Baxter wrote:Sean Kelly wrote:Bill Baxter wrote:Sean Kelly wrote:Java-style, with random access iterators overloading array operations. I can't remember if there was any clear preference for the hasNext/getNext vs. the atEnd/getVal approach, but I tend to favor the latter.Bill Baxter wrote:Huh. So what is your understanding of what the consensus was?Too bad the iterator discussions fizzled out without anything getting decided.I think the design was pretty well settled when things ended. The next step would be a sample implementation so folks could wrangle over syntax. It's on my "to do" list, but I'm a bit short on free time at the moment.Yes, this may be better. This was basically the point the last iterator discussion reached. I would like to make this even more fun by throwing in bidirectional iterators. :) Just to clarify my terminology here, a forward iterator needs three things: 1(R) a way to reference the data 2(T) a way to traverse the data 3(S) a way to signal the end of the data If one wants an interface with less than 3 methods, the above behaviors need to be combined in some way. In news://news.digitalmars.com:119/eiqltc$22c1$1 digitaldaemon.com I briefly reviewd three different ways used by three different languages Java combines (R+T) through next() and (S) through hasNext() Python combines (R+T+S) in next() (throwing an exception for S) There are downsides with all approaches. Java/Python disallows peek()ing without traversal. Python's exception requires more scaffolding at the use site. Now to bidirectional iterators. Separating R, T, S as three different methods, here are two ways a bidirectional iterator could be implemented: The value-style: BidirectionalIterator1(T) { T* begin; T* end; T* current; bool hasValue() { return cursor != end && cursor != (begin-1); } void moveNext() { current++; } void movePrevious() { current--; } T value() { return *current; } T value(T v) { return *current = v; } } Silly usage example: auto i = someIterator; while(i.hasValue) { if (i.value > x) i.moveNext; else i.movePrevious; } I like how succinct this turns out, but it has the disadvantage of internally needing two invalid values, one at the start and one at the end. Considering pointers internally, this means a pointer pointing before the start of an array, which is very bad. The other disadvantage is hasValue that has to check for both of these two cases. One alternative is the Java style version. Where the pointer/cursor lies conceptually between the elements instead of at an element, giving: BidirectionalIterator2(T) { T* begin; T* end; T* cursor; bool hasNext() { return cursor != end; } bool hasPrevious() { return cursor != begin; } void moveNext() { cursor++; } void movePrevious() { cursor--; } T next() { return *cursor; } T next(T v) { return *cursor = v; } T previous() { return *(cursor-1); } T previous(T v) { return *(cursor-1); } } auto i = someIterator; while(i.hasNext) { if (i.next > 3) i.moveNext; else i.movePrevious; } The disadvantage is requiring two additional methods (hasPrevious and previous), but the advantage is that it doesn't need more than 1 illegal value (pointing 1 past the end, which is well supported). Renaming next/previous into front/back or something may give more or less confusion. Probably the former. Apart from different method names, are there other variants? /OskarGood point. There's another problem related to iters sitting around a while, too, that I hadn't considered. If you have to call next() to get the first item then you'll also need some way to query if the iterator is in it's "pre-begin" state. So the next/atend approach only really works when there's no 'value' and 'next' is the only way to get the value. Ick. So maybe a for-ish way is better than while-ish way: for (; !iter.end; iter.next) { writefln(iter.value); } And have iterators start off valid (if not already at the end).I like next/value/(ptr) myself. Makes for very succinct while loops. ptr available where it makes sense. while(iter.next()) { writefln(iter.value); } while(iter.next()) { *iter.ptr = 17; }It's great for loops, but can be confusing when iterators stick around for a while. Say I have some code that operates on the current value of an iterator. With the next() approach, how do I know whether the iterator is valid? Still, perhaps a hybrid approach is best. Have next return true on success and offer an atEnd property as well.
Dec 15 2006
Oskar Linde wrote:Now to bidirectional iterators. Separating R, T, S as three different methods, here are two ways a bidirectional iterator could be implemented: The value-style: BidirectionalIterator1(T) { T* begin; T* end; T* current; bool hasValue() { return cursor != end && cursor != (begin-1); } void moveNext() { current++; } void movePrevious() { current--; } T value() { return *current; } T value(T v) { return *current = v; } } Silly usage example: auto i = someIterator; while(i.hasValue) { if (i.value > x) i.moveNext; else i.movePrevious; } I like how succinct this turns out, but it has the disadvantage of internally needing two invalid values, one at the start and one at the end.Not necessarily. The dummy node could be shared by both. This is one reason why circular linked-list implementations are so common. Things do admittedly get a bit weird for binary trees, however.Considering pointers internally, this means a pointer pointing before the start of an array, which is very bad.In C++, while a bidirectional iterator may be able to traverse in either direction, it still generally has some natural association as a forward or reverse iterator. That is, when the iterator is first returned from the sequence it was likely either initialized pointing to the first or last element. If it's the former then it's associated with forward iteration, if it's the latter then reverse iteration. For example, the C++ vector iterator is bidirectional (actually, random), but iterators returned by the begin() method are effectively forward iterators while iterators returned by the rbegin() method are effectively reverse iterators. Perhaps this is the correct approach to take here as well?The other disadvantage is hasValue that has to check for both of these two cases.True enough. But range-checking is range-checking. If it's possible for an iterator to go out of range and it's possible to check for this condition then one should do so, at least in debug builds.One alternative is the Java style version. Where the pointer/cursor lies conceptually between the elements instead of at an element, giving: BidirectionalIterator2(T) { T* begin; T* end; T* cursor; bool hasNext() { return cursor != end; } bool hasPrevious() { return cursor != begin; } void moveNext() { cursor++; } void movePrevious() { cursor--; } T next() { return *cursor; } T next(T v) { return *cursor = v; } T previous() { return *(cursor-1); } T previous(T v) { return *(cursor-1); } } auto i = someIterator; while(i.hasNext) { if (i.next > 3) i.moveNext; else i.movePrevious; } The disadvantage is requiring two additional methods (hasPrevious and previous), but the advantage is that it doesn't need more than 1 illegal value (pointing 1 past the end, which is well supported).The other disadvantage is that this returns to the original problem where it's impossible to determine whether an iterator points to a valid location without moving.Apart from different method names, are there other variants?See above. The C++ approach seems to make more sense to me, though I'm still mulling it over. There is a definite appeal to having iterators that are truly direction-agnostic, but as you've demonstrated above it does result in slightly weird implementation requirements. Since D is like C++ in that the one-past-the-end location is valid but one-past-the-beginning is not, it seems reasonable to preserve that behavior here, even if a more Java-like iterator design is used. Sean
Dec 27 2006
Jason House wrote:Sean Kelly wrote:This actually works for arrays, but only arrays. People have asked in the past that it be extended to work for arbitrary types, but no luck so far. ie. void doSomething( char[] buf ); doSomething( "abc" ); "abc".doSomething(); Both of the above calls should work, since char[] is an array type. SeanThat's exactly correct... Or at the very least the compiler must allow such properties to be added to them. I did try adding my own toString property (just in case there was neat hidden feature like that)* Enums do not (and can not) have a toString propertyThey don't at the moment. One could be added, I imagine, but it would have to be done in the compiler.
Dec 13 2006
Jason House wrote:I'm kind of doing a trial by fire method to learn D and how it works... I'm taking an existing open source project and converting it over. Here's the stuff that I've found / questions that I have.Great. Welcome.Thanks in advance for all the thoughtful responses. I know this is a long post! I've worked through the issues to get working code, but I think my issues will be hit by others. It seems that DTL and minTL [...]Never tried either one, so can't help you there.I know of no way in d to provide a const qualifier. It seems like the concept purely doesn't exist. minTL appears to have a workaround where it templates itself on a boolean value, and simply doesn't publish certain functions. When will a real const qualifier get added to the language? It seems really strange that a language that adds all kinds of contract programming wouldn't use const qualifiers / const types.That's right. D's const is limited to things whose value can be determined at compile time. So no const function parameters, for instance. I agree it is a bit odd. In particular I'd really like to have 'const inout' parameters for functions (though that actual nomenclature is nonsense). Right now declaring a parameter to be 'inout T' is the only way to make sure a huge value type T doesn't get copied on the stack. 'inout' is basically a T& in C++ terms. 'const T&' is probably more common in C++ than plain 'T&'. Sadly, D has no equivalent for it. My vote would be for an 'refin' or 'inref' parameter type in addition to the existing 'in', 'out', and 'inout' flavors. I think the reason D doesn't have it is just because C++ code gets pretty ugly with all those consts everywhere. Then there's const-correctness hell, when you decide to change one method to const and suddenly there's a ripple effect across your whole application. Until you get to the point where you discover that some 3rd party code out of your control is not const-correct and you ultimately resort to const_cast<>s. I guess I'm used to it, though. :-) That doesn't seem such a bad thing to me if it results in a program that more clearly documents which things can be modified. I'm certainly glad that D is not Fortran where every parameter is basically inout, and you have to read the documentation to see if what you pass in is going to be clobbered or not.After banging my head on printing stuff for a long time, I've come to a few conclusions: * The C++ equivalent to std::ostream& operator << (std::ostream &out, const type &x) does not existI think std.stream.OutputStream.write is the closest there is. But mainly you can't overload operators outside of classes in D. And also I think template lookup across modules doesn't work. What I recall being the killer the last time I brought up something like this was that Walter says it's too tricky to get Koenig lookup working. I'm not really sure what the deal is, but I think D is going to need it eventually. Correct me if I'm wrong, folks, but right now the only way to do things like C++'s operator<< (the compile-time polymorphism functionality, not the syntax) is to have an exhaustive list of static if, else static if, ... cases inside a template. Thus users can't add their own overrides in a different module.* Custom types use the toString propertyYes.* Enums do not (and can not) have a toString propertyI guess not. But of course you can make a toString non-property for your enum. writefln(toString(myEnum)) instead of writefln(myEnum).* I have found no way to determine (in a templated class) if a type is printable or not. static if(is(typeof(T))) comes close, but my very first test using ints failed.You mean printable as in writefln(x) will work on it? Hmm. That is kinda tricky. I think there's a way to do it, but it will likely involve lots of static if's checking one-by-one for types that are printable. Ultimately, though, what's "printable" boils down to what things std.format.doFormat supports, and that's ultimately only determinable at runtime.The special unittest member function doesn't get built in with -unittest unless the actual class is used in some way (and then one copy of the unittest funciton gets run for each type). I'd really like to see some way for this to work. for example, class foo(T){ ... unittest{ foo!(int) sample; ...} } does not run unless other code instantiates foo!(U)That sounds like a bug. I didn't even realize you could put unittests inside of classes. All the code I've seen has the unittests outside of the class.In my early efforts at doing operator overloading, I wrote opCmp and then was shocked when my unit test showed that == didn't even call opCmp. It silently did something wrong. This seems like a gotcha built into the language that should probably get remedied.Like what? I'm not really to up on opEquals/opCmp. Should you get a warning if you only override opCmp? Or an error?I couldn't find a way to reinitialize a variable back to a default value... For example class foo(T){ T[] bar; void func(){bar[3] = new T();} } won't compile. I'm not too sure why this is the case.bar[3] = T.init is what you need for a value type. --bb
Dec 13 2006