July 30, 2004
Interesting... As long as we're dreaming* up stuff, here's a few more ideas...

T map(S,T)(S x)
{
    ...
}

=>

template map(S,T)
{
    T map(S x)
    {
        ...
    }
}

(and then something a bit more far out...)

If "name: type" order was reversed (*)

map(S,T)(x: S): T

If there were inline type parameters

map (x: $S): $T

and perhaps

map (x: $S: {A, B} = A): $T

Explicit instantiation, e.g. map!(int,bit) -- $S = int, $T = bit. I like that its concise, but I'm not too sure about its viability.

"Andy Friesen" <andy@ikagames.com> wrote in message news:cecgd6$231k$1@digitaldaemon.com...
> C. Sauls wrote:
>
> >> And of course that syntax would not work because it takes the second
and
> >> third interfaces as new parameters :).
> >
> >
> > And then comes the joy of my suggested way of doing it... it opens up
> > this possibility:
> >     template foo (T : Interface1 && Interface2 && Interface3)
> > -or-
> >     template foo (T : Interface1 and Interface2 and Interface3)
> >
> > Although after looking at it I started wondering about my (signed && enum) trick... I don't think it would be good, at least not that way.  I get stuck wondering how to interpret something like (signed && struct)... What would make a /struct/ "signed" or "unsigned"??  So it could lead to ambiguity, and nobody likes ambiguity... okay well some of the time.
>
> Say we decide on some operations that can be done on types:
>
>      T1 == T2 - T1 and T2 are the same type
>      T1 >  T2 - T1 is a subclass of T2? (iffy.  T1 is a superset of T2)
>      T1 >= T2 - subclass or equal
>      D in T   - declaration D is a member of instances of T
>      T :  TE  - T is deduced from type expression TE
>
> Then we can borrow a little from C#, a little from ML, and do something like this:
>
>      template ComplexTemplateThing(A, B, C, D)
>          where
>              A > Stream && // A must extend stream
>              B > struct && // B "extends" struct
>              void opApply(inout char[]) in C && // C instances must have
> an opApply method
>
>              D : null[null] // specialization: 'null' matches all types.
>                             // (ML uses _ the same way)
>                             // Type D can be any associative array
>               ||            // or
>              D : C[]        // permit D to be an array of C
>      { ... }
>
> The only problem is that we've started turning into Lisp all over again.
:)
>
>   -- andy


July 30, 2004
Matthew wrote:

> Notwithstanding that, it's my intent all along that DTL will also support Java-style enumeration and STL-style enumeration. I don't see why anyone should be forced to go one way, when we can support them all (without efficiency costs of features not being used, of course).

That's exactly what Troll Tech is doing with their (still unreleased) Qt 4.0. I also like having a choice.
July 30, 2004
On Fri, 30 Jul 2004 17:53:20 +1000, Matthew wrote:

> 
> "teqDruid" <me@teqdruid.com> wrote in message news:pan.2004.07.29.15.13.34.724295@teqdruid.com...
>> I've read over your rant.  I'll not pretend to understand all of it, and I don't have any suggestions for your specific problems, except to that the Java route is not the way to go. I'm a Java guy, and I hate the Java collections API.
>>
>> Whenever I work on an open-source project, I put my code in a publicly accessable repository (a subversion repository, specifically) and I generally commit my code to it after each new change (even small changes, like a since bug fix) and generally before I stop for the day.  This way, I can get input from others, not that there are many (hell, let's face it: any) followers of my projects.  (Plus, the code gets backed up, but that's OT.) It's kind of a "release early, release often" approach (btw, if you haven't read ESR's "The Cathedral and the Bazaar", it's a good read.) I think your decision to release what you've got in a day or two is a good one. It's always good to have more people reading the code. The more perspectives one can get input from, the more successful a project will be, in my opinion.  I would even encourage you to put the project on dsource, and commit to the repository often.  I know I'd definately be more help giving advice (or even patches) if I could see the entire source.
> 
> The problem I've had is that the things that have held me up are not things that anyone other than Walter could help me with, since they've been compiler bugs and (missing) language features. Were I to have posted it, people would've seen nothing more than non-compilable, or crashing, code

Yes, but you said that you don't have time to "boil-down" code for submission.  Merely posting broken code, I'm sure people would be willing to help prepare bug reports and testcases for Walter.
July 30, 2004
In article <cec9sf$20qk$1@digitaldaemon.com>,
 "Matthew" <admin@stlsoft.dot.dot.dot.dot.org> wrote:

> There's no implicit instantiation. So to use an iterator class with a
> "generic" algorithm either means that one uses a
> template algorithm and explicitly instantiates its type, or one uses a
> non-template algorithm that manipulates via an
> interface and passes only types that inherit from that interface to it.
> 
> The DTL containers can all inherit from an otherwise defaulted second
> template parameter, which defines their "parent"
> interface, as in:
> 
>     Vector!(int, IObjectContainer)    v;
>     List!(int, IObjectContainer)        l;
> 
> Now v and l are both polymorphically related about the IObjectContainer
> interface, and either can be passed to a
> function that knows how to use an IObjectContainer.
> 
>     dump(IObjectContainer c);
> 
>     dump(v);
>     dump(l);
> 
> The self same thing would apply to iterators. We would define iterator
> interfaces, either Object-based (i.e.
> IObjectIterator), or parameterised (e.g. IIterator!(int), from which our
> containers' iterator classes would derive.
> Let's say we'll derive the iterator classes for List!(T) and Vector!(T) from
> IIterator!(T), thus:
> 
>     int accumulate(IIterator!(int) from, IIterator!(int) to, int initial);
> 
>     int     r1    =    accumulate(v.begin(), v.end(), 0);
>     int     r2    =    accumulate(l.begin(), l.end(), 0);
> 
> But this is not generic programming, or at least not as I understand the
> term. accumulate() is not a generic algorith,
> it is a specifi function, whose non-template parameters are the type
> IIterator!(int). To accumulate BigInts, or doubles,
> we'd need another implementation of accumulate() for each.
> 
> Of course, one could take the next step, and get almost all the way there,
> 
>     template accumulate(T) { T accumulate(IIterator!(T) from, IIterator!(T)
>     to, T initial)
>     {
>         . . . accumulation ...
>     }}
> 
>     Vector!(BigInt, IObjectContainer)    v;
>     List!(double, IObjectContainer)        l;
> 
>     BigInt      r1    =    accumulate!(BigInt)(v.begin(), v.end(), new
>     BigInt(0));
>     double     r2    =    accumulate!(double)(v.begin(), v.end(), 0.0);
> 
> But this is still not generic programming. There are several problems:
>
> 1. One must specify the type in the explicit parameterisation of
> accumulate(). This can be considered a minor problem in
> most cases

It's a bit of extra typing, I'll give you that.  But with the aliases for instances bug fixed. You could presumably do:

accumulate!(v.baseType)(v.begin(), v.end(), 0.0)

now.

> 2. The processing is necessarily inefficient, because it's using virtual
> functions to access the elements, via the
> interface

Granted.  However, if D would allow you to specify greater restrictions on templates, as was proposed in this thread, (and walter liked) then the accumulate function could accept not a Iterator!(T) from.   But rather a T, thus allowing it to be non-virtual.

Presumably just requiring T to be a child of a IObjectContainer.

Would that still cause the methods to be virtual though, just because they're conforming to an interface?  Probably would, silly me.

Could you give an example of how the accumulate function would be defined in C++?


> 3. The definition and use of accumulate!() is effectively tied to
> IIterator!(). Try incorporating another accumulate!()
> based on another interface into the mix!

D should find the most specialized case of accumulate.  If it doesn't, this needs to be fixed.

> 4. There is no mechanism - or at least I've not thought of one - for
> short-circuiting operations based on the iterator
> refinement. In other words, how do we get a random access iterator class to
> do an efficient distance()? (Actually, I'm
> having some ideas now ... but it's likely to be nasty stuff.)

Not sure what you mean here. I presume you mean a templated distance specialized for a RandomAccessIterator?  Shouldn't that work if D finds the most specialized case, rather than the first one it finds?
July 30, 2004
"Matthew" <admin.hat@stlsoft.dot.org> wrote in message news:cecug0$2ag9$1@digitaldaemon.com...
> > I think I can fix that.
>
> If you can, I will kiss you. :)

That would get me in trouble. I recommend instead sending large quantities of cash.


July 30, 2004
> requirements Bob {
>    interface Interface1,..
>    typeof ParentClass,..
>    type unsigned,..
> }

Love it.  It covers the complex type filters, and makes the code more readable by abstracting filters.  Maybe the keyword should should be filter instead of requirements.

-Owen


July 30, 2004
"Matthew" <admin.hat@stlsoft.dot.org> escribió en el mensaje
news:cecug1$2ag9$2@digitaldaemon.com
| "Charlie" <Charlie_member@pathlink.com> wrote in message
| news:cebotu$1plh$1@digitaldaemon.com...
|||    template Vector(T, B = EmptyBase)
|||    {
|||        class Vector
|||            : public BaseSelector!(B).selected_type
||
|| I realize you do alot of C++ and D programming, so you want to keep the
syntax
|| roughly the same, but this looks dangerously close to C++.  Why noy use the D
|| way :)
||
|| class Vector(T,B = EmptyBase) : BaseSelector!(B).selected_type
|
| I do a lot of programming in a lot of languages, and I always lay out my
| inheritance lists in the same way. AFAIAC it's got nothing specifically to do
with
| C++.
|

What Charlie meant there was that you don't need the "template" keyword if you're only defining a templated class. Instead you could use the short syntax: class C(T) {...} Also, "public" is default in D. I don't know if that holds true for inheritance, though. If it's also by default there, then it wouldn't be neede in your example.

That relates to what he said later:

|| I only mention this because I wonder how much ( unconsiously ) your applying
|| C++'s soloutions to D.
|
| Undoubtedly. I am also _consciously_ applying ideas from many languages. Is
that a
| problem? Since D doesn't yet have established methodologies for all this kind
of
| thing - apart from foreach - what would you suggest instead?

-----------------------
Carlos Santander Bernal


July 31, 2004
"Carlos Santander B." <carlos8294@msn.com> wrote in message news:ceeigl$74j$1@digitaldaemon.com...
> "Matthew" <admin.hat@stlsoft.dot.org> escribió en el mensaje
> news:cecug1$2ag9$2@digitaldaemon.com
> | "Charlie" <Charlie_member@pathlink.com> wrote in message
> | news:cebotu$1plh$1@digitaldaemon.com...
> |||    template Vector(T, B = EmptyBase)
> |||    {
> |||        class Vector
> |||            : public BaseSelector!(B).selected_type
> ||
> || I realize you do alot of C++ and D programming, so you want to keep the
> syntax
> || roughly the same, but this looks dangerously close to C++.  Why noy use the D
> || way :)
> ||
> || class Vector(T,B = EmptyBase) : BaseSelector!(B).selected_type
> |
> | I do a lot of programming in a lot of languages, and I always lay out my
> | inheritance lists in the same way. AFAIAC it's got nothing specifically to do
> with
> | C++.
> |
>
> What Charlie meant there was that you don't need the "template" keyword if you're only defining a templated class. Instead you could use the short syntax: class C(T) {...} Also, "public" is default in D. I don't know if that holds true for inheritance, though. If it's also by default there, then it wouldn't be neede in your example.

Gotcha

I'll migrate to the D way for templates, then, but I'm keeping with my explicit access declarations. It aids readability, discoverability and instrumentability (and ilityability <G>), and costs but a couple of axon firings.



August 01, 2004
On Thu, 29 Jul 2004 16:35:10 +0000 (UTC), Sean Kelly <sean@f4.ca> wrote:
<snip>
> But this raises an interesting point.  One useful but little mentioned feature
> of C++ is that primitive types support default constructor semantics just like
> user defined classes do.  For generic programming it might be nice to have the
> same thing:
>
> MyClass c = new MyClass();
> int i = new int(); // equivalent to "int i;"
>
> This makes the difference between pointers and nonpointers a tad confusing but
> it would make life much easier in some cases.

Or, go the other way, as Arcane Jill has suggested in the past.

MyClass c(1,2,3);   //equivalent to "MyClass c = new MyClass(1,2,3);
MyStruct s(4,5,6);  //give us struct constructors :)
int i(1);           //equivalent to "int i = 1;"

The only confusion I see here is that the class is on the heap and the others on the stack so they're different but they don't look it. Then again who said you have to get rid of what we currently have, all we really need to do is add this option.

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
August 01, 2004
> To achieve that D *must* support the currently unmatched power of C++.

Hmm, isn't LIPS much more powerfull?