December 03, 2003
In article <bqg9gu$23bd$1@digitaldaemon.com>, Hauke Duden wrote:
> davepermen wrote:
>> swap(a,b); is still unbeatable....
> 
> I agree completely, with all your points!
> 
> The instance() form of instantiation is a nuisance that I never understood the need for. Is it just because the are no unambiguous parantheses "left"? I'm sure we can find some unused token to replace the <>! If you use templates a lot then all this "instance" stuff

Maybe replacing <> with something else is not the way to go at all... at least if you look at where Java and C# are going to. Having a template syntax _different_ from <> will at any case make D an oddball in the eyes of many programmers.

> And while I'm at it: the namespaces may sound nice in theory - making templates generic constructs that you can put almost anything into - but in practice they make the code less readable.

True. At least if you're accustomed to the C++ way. In C++, you *have* to make your templates classes -- even if class wasn't the proper way to structure the code in the first place. This is similar to Java, which actually forces you to make *all* modules classes, even when they don't have generic arguments! In fact, Java is more consistent than C++ because there isn't anything (functions, enums, ...) that you *couldn't* genericize! Classes are the beginning and the end of all. We are the Class. You will be ... classimilated.

This isn't to say that the D template approach is totally right. In D, you can template anything *except* the things that you usually want to template: classes, functions (with implicit instantiation, s'il vous plaît), typedefs (which are sorely missing in -- current -- C++!)...

> For example, templates are most often used in collection classes. If you're writing a single collection class, then you face a naming problem: what should the name of the namespace be and then what do you call the class?
> 
> If templates stay the way they are now, then I'm prediciting that we will see a lot of the following in D:
> 
> template TLinkedList(T)
> {
> 	class TheClass
> 	{
> 	...
> 	}
> }

True.

> You have to give your class two names! One for that obligatory namespace and one for the class itself. And you have to specify both names when you use it ... pretty burdensome, if you ask me.

True.

> And no, typedefs do not really provide much of a help here either, because it is in the nature of templates that they are written without knowing the types that they are going to be used with. So adding dozens of typedefs of the form
> 
> typedef instance TLinkedList(int).TheClass TLinkedList_Int;
> typedef instance TLinkedList(MyClassA).TheClass TLinkedList_MyClassA;
> typedef instance TLinkedList(MyClassB).TheClass TLinkedList_MyClassB;
> 
> is out of the question. Besides, the manual name mangling that would be required for such typedefs isn't exactly a property you'd expect from a modern language.

True.

> There may be uses for template namespaces, but personally I never found myself wishing for that feature in C++. If the namespace was optional, then it would be a nice "icing on the cake" feature, but the way it is now it is a nuisance.

I found one place where it would be convenient if a module had generic arguments, using syntax not particularly C++ nor D:

enum Byte_Order { little_endian, big_endian }

module Endian<Byte_Order byte_order>
{
    T fetch<T : Arithmetic_Type>(const byte* data)
    {
        // fetch result from address data assuming byte order byte_order
    }

    void store<T : Arithmetic_Type>(T value, byte* data)
    {
        // store value to address data assuming byte order byte_order
    }
}

Then I could use Endian<little_endian>.fetch<int>(address) to get a
value from address assuming it's stored in little endian, and
Endian<big_endian>.store(value, address) to store it in big endian form.

But ah well, this is just cosmetic stuff. I can just as well use a templated class in C++, with two static functions, or two free-standing functions. It's just that the Endian module isn't really *conceptually* a class. I guess you could find a lot of modules that you'd want to templatize, if you'd start doing some serious metaprogramming stuff.

> Couldn't the template and class definition be merged? Like
> 
> template class TLinkedList(T)
> {
> 	...
> }
> 
> as a synonym for
> 
> template <currentnamespace>(T)
> {
> 	class TLinkedList
> 	{
> 	}
> }

I like this proposal. It would be nice to get templatized functions, typedefs, aliases and even enums with the same syntax. Hypothetical stupid example:

template class TLinkedListSynchronized(T) { ...}
template class TLinkedListSingleThreaded(T) { ...}

version (SingleThreaded)
{
    template alias TLinkedListMultiThreaded(T) LinkedList(T);
}
version (MultiThreaded)
{
    template alias TLinkedListSynchronized(T) LinkedList(T);
}

If this proves difficult to parse, then put the argument list after the keyword "template":

template(T) class LinkedList
{
    ...
}

template(T) T min(T a, T b)
{
    return a < b ? a : b;
}

I don't know what you'd use template enums for, but why not allow them if you allow everything else?

> Hoping this post doesn't sound too negative. I just think these issues are too important for the language to just let them pass...

True.

Generic programming is an essential feature for an industry standard programming language. Metaprogramming will be the next big step. If one could make *that* leap, one might get generic programming for free as a side effect. But that won't happen in a couple of years...

-Antti

December 04, 2003
In article <bqlhgf$mr7$1@digitaldaemon.com>, Ilya Minkov says...
>
>Mark Brudnak wrote:
>> What about the case:
>> 
>> array[$-2..$] /* slices the last three elements */
>
>array[-2..]
>
>with the limitation, that this minus may not be a part of the argument, but only a unary minus. Hell, make it a "[-"-operator!  A negative value of arguments should be still out-of-bounds error.
>
>-eye
>

I much prefer ":" as it's more concise, and i'm allergic to Pascal, I think.

array[:]   // a slice of the whole array
array[-5:] // last five elements
array[:-5] // all but last five

And contrary to what Ilya says, D should definitely steal this from Python:

some = array[-2] //next to last component

this is absolutely beautiful if you have a circular list or something and have to do something based on other members. Convolution type things.


/*
foreach(int i, inout float f; a)
{
//this will overstep the bounds so we need a special case for the last two
f = (a[i+1] + a[i+2])*0.5
}
*/

foreach(int i, float f; a)
{
//instead we start at the next to latest
a[i-2] = (a[i-1] + a[i])*0.5
}

Nonni

PS: sorry for (more or less) reposting, but last time got garbled, and this fit
even better here.


December 04, 2003
In article <bqlvrg$1cft$1@digitaldaemon.com>, Jon Thoroddsen says...

>I much prefer ":" as it's more concise, and i'm allergic to Pascal, I think.

Call it "much" more concise. :)

>array[:]   // a slice of the whole array
>array[-5:] // last five elements
>array[:-5] // all but last five

These ones should all work with my proposal, as - would be a unary operator right within this expression. Whatever variable is here in place of your "5" should be nontheless positive.

>And contrary to what Ilya says, D should definitely steal this from Python:

It's not exactly my opinion i was stating, i was just looking for a compromise. Walter is strongly against a forced neg check at runtime for every array access, since this is bad for performance. And we *really* want to rival not only with Java, but also with C++. ;) So i propose that whenever it is possible to derive that negativity from expression syntax, it should be done, else it is an error.

>some = array[-2] //next to last component

This would work.

>this is absolutely beautiful if you have a circular list or something and have to do something based on other members. Convolution type things.

--- 8< --- >8 ---

Walter is against real circularity. It has to be exceptionally rare, whereas acessing the n-th element from the end is very common and i would wish there be some neat syntactic way to express it. However, it's not really a problem if there isn't. There ought to be quite more serious issues.

-eye


December 04, 2003
"Ilya Minkov" <Ilya_member@pathlink.com> wrote in message news:bqno46$trs$1@digitaldaemon.com...
> In article <bqlvrg$1cft$1@digitaldaemon.com>, Jon Thoroddsen says...
>
> >I much prefer ":" as it's more concise, and i'm allergic to Pascal, I
think.
>
> Call it "much" more concise. :)
>
> >array[:]   // a slice of the whole array
> >array[-5:] // last five elements
> >array[:-5] // all but last five
>
> These ones should all work with my proposal, as - would be a unary
operator
> right within this expression. Whatever variable is here in place of your
"5"
> should be nontheless positive.
>
> >And contrary to what Ilya says, D should definitely steal this from
Python:
>
> It's not exactly my opinion i was stating, i was just looking for a
compromise.
> Walter is strongly against a forced neg check at runtime for every array
access,
> since this is bad for performance. And we *really* want to rival not only
with
> Java, but also with C++. ;) So i propose that whenever it is possible to
derive
> that negativity from expression syntax, it should be done, else it is an
error.

True true.  You probably already said this, Ilya, but it would seem that in this context, there should be [- and :- tokens, or that somehow the unary minus is not lexically part of some int literal.  I think this is already the case.

It would not be an unreasonable restriction to have the "negativeness" be part of hte expression and not part of the variable.  It might be tricky to explain to newbies though.  It would have to be in the FAQ.  It would be worth having though.

> >some = array[-2] //next to last component
>
> This would work.
>
> >this is absolutely beautiful if you have a circular list or something and
have
> >to do something based on other members. Convolution type things.
>
> --- 8< --- >8 ---
>
> Walter is against real circularity. It has to be exceptionally rare,
whereas
> acessing the n-th element from the end is very common and i would wish
there be
> some neat syntactic way to express it. However, it's not really a problem
if
> there isn't. There ought to be quite more serious issues.
>
> -eye

Circularity is still best handled with modulo % or and &.  You can make your own container that always does modulo on the index.

Sean


December 05, 2003
"Jon Thoroddsen" <Jon_member@pathlink.com> wrote

<snip>

> I much prefer ":" as it's more concise, and i'm allergic to Pascal, I
think.
>
> array[:]   // a slice of the whole array
> array[-5:] // last five elements

This would actually slice the last *six* elements, $-5, $-4, $-3, $-2, $-1, and $

> array[:-5] // all but last five


>
> And contrary to what Ilya says, D should definitely steal this from
Python:
>
> some = array[-2] //next to last component

This breaks symetry in the notation.  In your scheme,

first element:     array[0]
last element:      array[-1]

To be consistent, it should be:

first element:    array[0]
last element:    array[-0]

second element:              array[1]
second to last element:    array[-1]

but as we know -0 = 0.

It this worth the economy of saving one or two key strokes??  Especially since the current situation is

int end = arrary.length -1 ;
slice = array[end-4..end] ;     /* slices the last five elements */

...or...

slice = array[(array.length-5)..(array.length-1)] ;     /* slices the last
five elements */

It would seem a huge improvment to introduce the $ as a shortcut for "array.length - 1" then

slice = array[$-4..$] ;     /* slices the last five elements */

We save two keystrokes by using your notation

slice = array[-4..] ;     /* slices the last five elements */

at the expense of (IMO) clarity.

>
> this is absolutely beautiful if you have a circular list or something and
have
> to do something based on other members. Convolution type things.
>
>
> /*
> foreach(int i, inout float f; a)
> {
> //this will overstep the bounds so we need a special case for the last two
> f = (a[i+1] + a[i+2])*0.5
> }
> */
>
> foreach(int i, float f; a)
> {
> //instead we start at the next to latest
> a[i-2] = (a[i-1] + a[i])*0.5
> }
>
> Nonni
>
> PS: sorry for (more or less) reposting, but last time got garbled, and
this fit
> even better here.
>
>


December 05, 2003
Mark J. Brudnak wrote:
>>array[:]   // a slice of the whole array
>>array[-5:] // last five elements
> 
> 
> This would actually slice the last *six* elements, $-5, $-4, $-3, $-2, $-1,
> and $

No, not if it works as in Python. In Python, -1 refers to the last element of the array, so a slice starting at -5 consists of the last 5 elements.

> Python:
> 
>>some = array[-2] //next to last component
> 
> 
> This breaks symetry in the notation.  In your scheme,
> 
> first element:     array[0]
> last element:      array[-1]
> 
> To be consistent, it should be:
> 
> first element:    array[0]
> last element:    array[-0]
<snip>
> but as we know -0 = 0.

That's what many programmers think when they see Python slices for the first time. I did too. But it's all just a matter of definition. If you define that indices refer to the left "border" of array slots, then the Python way is the consistent one.

Consider the following array (view with fixed width font)

| a | b | c | d |
^           ^   ^
0          -1  -0

a,b,c,d are the values in the array slots, the numbers below are the indices, referring to the left border of the corresponding slot. Viewed like this, -0 would refer to the (non-existent) element following d and -1 refers to d itself.

Also, as you point out, if you define -0 as the last element, then you cannot reference it, since -0 = 0. So the Python way is really the only way to do it if you want to avoid having to pass an expression of some kind (like your $-2) instead of an integer value (-2).

Also, maybe surprisingly, this system actually works very well in practice. Up to now, I never got confused by the indexing scheme. And I think most Python programmers will agree with that.


Hauke
December 05, 2003
"Mark J. Brudnak" <mjbrudna@oakland.edu> wrote in message news:bqq2j3$1av8$1@digitaldaemon.com...
>
> "Jon Thoroddsen" <Jon_member@pathlink.com> wrote
> > array[:]   // a slice of the whole array
> > array[-5:] // last five elements
>
> This would actually slice the last *six* elements, $-5, $-4, $-3, $-2,
$-1,
> and $
>
> > array[:-5] // all but last five

Icon apparently does it the same way as Python.

> It this worth the economy of saving one or two key strokes??  Especially since the current situation is
>
> int end = arrary.length -1 ;
> slice = array[end-4..end] ;     /* slices the last five elements */

No, in current DMD this would slice off the four elements just before the last element in the array, not including the last element.

Sean



December 19, 2003
"Patrick Down" <pat@codemoon.com> wrote in message news:Xns944555EF3300Bpatcodemooncom@63.105.9.61...
> Felix <Felix_member@pathlink.com> wrote in news:bqhfsl$p7k$1@digitaldaemon.com:
>
> > Why cannot use simply instancetype(newinstancetype) and the compiler will know that, if instancetype is a "instance type", then it will instantiate it; and that's all
>
> I agree that would be best.  You will have to ask Walter but I belive the reason for the 'instance' keyword is to resolve some context sensitivity issue with the langauge grammer.

You're right. It would not parse in a context-free manner.


1 2 3 4
Next ›   Last »