Am I getting this all right?

Chris Nicholson-Sauls ibisbasenji at gmail.com
Wed Dec 13 21:02:00 PST 2006


Jason House wrote:
> 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.

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

# import cashew .utils .array ;
# import std           .stdio ;
#
# void main (char[][] args) {
#   char[][] stack ;
#
#   foreach (x; args)
#     stack.push(x);
#
#   while (stack.length)
#     writefln("%s", stack.pop);
# }

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:

# struct Tree(int B = 2, T) {
#   version (Tree_NoWarnings) {} else
#     static if (B == 0)
#       static assert(false, "A tree with zero branches is just useless.");
#     else static if (B == 1)
#       static assert(false, "A tree with only one branch may as well be an array.");
#
#   alias Tree!(B, T) Node ;
#
#   Node*[B] children ;
#   T        value    ;
#
#   int walkDepth (int delegate(inout Node) dlg) {
#     int result ;
#
#     foreach (x; children)
#       if (x && (result = x.walkDepth(dlg)))
#         goto L_end;
#     result = dlg(this);
#
#   L_end:
#     return result;
#   }
#
#   int walkBreadth (int delegate(inout Node) dlg) {
#     int     result          ;
#     Node*[] gen    = [this] ,
#             next            ;
#
#     while (gen.length) {
#       foreach (x; gen) {
#         if (result = dlg(x.value))
#           goto end;
#         foreach (y; x.children)
#           if (y)
#             next ~= y;
#       }
#       gen = next.dup;
#       next.length = 0;
#     }
#
#     end:
#       return result;
#   }
# }

(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.)

>>> * Enums do not (and can not) have a toString property
>>
>> They don't at the moment.  One could be added, I imagine, but it would 
>> have to be done in the compiler.
> 
> 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)

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:

# enum Qubit {
#   T, F, TT, TF, FT, FF
# }
#
# const char[][Qubit] QubitNames ;
#
# static this () {
#   QubitNames[Qubit.T ] = "T"  ;
#   QubitNames[Qubit.F ] = "F"  ;
#   QubitNames[Qubit.TT] = "TT" ;
#     // ... etc
# }

> 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.

>>> 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 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.

I for one think the default opEquals probably /should/ use opCmp... but alas.

>>> 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.
> 
> 
> 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)

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.

# bar.length = size; // won't reallocate unless size is bigger than before
# foreach (inout x; bar)
#   x = new T;


Above all, have fun with your new D experience.  :)

-- Chris Nicholson-Sauls


More information about the Digitalmars-d-learn mailing list