www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Any word on the return-type const syntax?

reply "Janice Caron" <caron800 googlemail.com> writes:
I know there was a suggestion in the Walter/Andrei document, but has
it been finalised?

I'm referring to the ability to define the constancy/invariance of the
return type in terms of the constancy/invariance of a calling
parameter, in order to avoid having to write the same function three
times.
Dec 07 2007
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 I know there was a suggestion in the Walter/Andrei document, but has
 it been finalised?
 
 I'm referring to the ability to define the constancy/invariance of the
 return type in terms of the constancy/invariance of a calling
 parameter, in order to avoid having to write the same function three
 times.

That can now be done with a template.
Dec 07 2007
next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Walter Bright Wrote:

 Janice Caron wrote:
 I know there was a suggestion in the Walter/Andrei document, but has
 it been finalised?
 
 I'm referring to the ability to define the constancy/invariance of the
 return type in terms of the constancy/invariance of a calling
 parameter, in order to avoid having to write the same function three
 times.

That can now be done with a template.

Does that mean the return keyword affecting an input parameter won't ever be implemented? IMHO, the return keyword is more elegant than using templates.
Dec 07 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 Here's a typical problem.
 
     class MyArray(T)
     {
         T[] a;
 
         T* ptr() { return a.ptr; }
         const(T)* ptr() const { return a.ptr; }
         invariant(T)* ptr() invariant { return a.ptr; }
     }
 
 A template helps how, exactly?

TransferConst!(U,T) ptr(this U)() { return a.ptr; }
Dec 07 2007
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 On 12/8/07, Walter Bright <newshound1 digitalmars.com> wrote:
 Janice Caron wrote:
 Here's a typical problem.

     class MyArray(T)
     {
         T[] a;

         T* ptr() { return a.ptr; }
         const(T)* ptr() const { return a.ptr; }
         invariant(T)* ptr() invariant { return a.ptr; }
     }

 A template helps how, exactly?


There are several things I don't understand about this example. You seem to be suggesting that TransferConst!(U,T) resolves to K(T)*

I should have written: TransferConst!(U,T*)
 The next thing I don't understand is the notation
 
     ptr(this U)()
 
 How does that even parse? I'm not familiar with this means of
 specifying template parameters. What does it mean?

It means U is given the type of the 'this' pointer. This was added in 2.008.
 The third thing I don't understand is, I see no specication of the
 constancy of the member function itself. I expect to see either
 const-at-the-end, or const-at-the-start, but I see neither. Where is
 it?

It's in wherever the 'this' pointer came from, i.e. from the caller.
 And of course, my final question has to be, is this function still
 virtual?

No.
 I think my way looks most readable, but you tell me.

The larger the function body is, the less readable and more error prone duplicating it becomes.
 One really important point to consider is that you need EXACTLY ONE
 instantiation of the function. That is, the bytes of machine code
 which comprise the function would be identical in all three cases, and
 therefore need to exist only once. I suspect that your template idea,
 in addition to robbing me of virtuality, would also instantiate the
 function three times.

Currently, it would instantiate it three times. This is a more general problem, though, and there are many other instances where it happens. Eventually, the best solution should be in the linker being able to coalesce identical comdat sections.
Dec 08 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 But I think there's still a problem. If I write
 
     class MyArray(T)
     {
         T[] a;
         TransferConst!(U,T*) ptr(this U)()
         {
             return a.ptr;
         }
     }
 
     const MyArray!(int) aa;
     auto p = aa.ptr;
 
 Then presumably it won't compile, becase aa is not mutable,

Template member functions are not instantiated until they are called.
Dec 08 2007
parent reply Sean Kelly <sean f4.ca> writes:
Walter Bright wrote:
 Janice Caron wrote:
 But I think there's still a problem. If I write

     class MyArray(T)
     {
         T[] a;
         TransferConst!(U,T*) ptr(this U)()
         {
             return a.ptr;
         }
     }

     const MyArray!(int) aa;
     auto p = aa.ptr;

 Then presumably it won't compile, becase aa is not mutable,

Template member functions are not instantiated until they are called.

Or until they are aliased, to be pedantic. Sean
Dec 09 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Sean Kelly wrote:
 Walter Bright wrote:
 Janice Caron wrote:
 But I think there's still a problem. If I write

     class MyArray(T)
     {
         T[] a;
         TransferConst!(U,T*) ptr(this U)()
         {
             return a.ptr;
         }
     }

     const MyArray!(int) aa;
     auto p = aa.ptr;

 Then presumably it won't compile, becase aa is not mutable,

Template member functions are not instantiated until they are called.

Or until they are aliased, to be pedantic.

It's an important point though. Does C++ behave that way? I was under the impression that in C++ I could create typedefs of templated structs and classes that wouldn't get instantiated unless actually used. --bb
Dec 09 2007
parent reply guslay <guslay gmail.com> writes:
Bill Baxter Wrote:

 Sean Kelly wrote:
 Template member functions are not instantiated until they are called.

Or until they are aliased, to be pedantic.

It's an important point though. Does C++ behave that way? I was under the impression that in C++ I could create typedefs of templated structs and classes that wouldn't get instantiated unless actually used.

Instantiation is not required with typedef, because the following is legal C++ class Foo; typedef vector<Foo> vfoo_t; // 1 but not vector<Foo> vfoo; // 2 - cannot instantiate I don't know however if an implementation *would* instantiate //1 if it *could* (ie. if Foo was defined).
Dec 09 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
guslay wrote:
 Bill Baxter Wrote:
 
 Sean Kelly wrote:
 Template member functions are not instantiated until they are called.


the impression that in C++ I could create typedefs of templated structs and classes that wouldn't get instantiated unless actually used.

Instantiation is not required with typedef, because the following is legal C++ class Foo; typedef vector<Foo> vfoo_t; // 1 but not vector<Foo> vfoo; // 2 - cannot instantiate I don't know however if an implementation *would* instantiate //1 if it *could* (ie. if Foo was defined).

I think you are correct. Also C++ has a different way to do explicit instantiations: template<class T> class Array { void mf(); }; template class Array<char>; // explicit instantiation template void Array<int>::mf(); // explicit instantiation They wouldn't need that syntax if typedefs already instantiated. The instatiate-if-aliased behavior of D is a little annoying because it means you can't create convenience aliases of your templates without bloating up your executable. For linear algebra types, for instance, many C++ libraries will provide typedefs for the most common combinations of floating point type and number of components, maybe a dozen or so of these. --bb
Dec 09 2007
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Janice Caron wrote:
 On 12/9/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:
 The instatiate-if-aliased behavior of D is a little annoying because it
 means you can't create convenience aliases of your templates without
 bloating up your executable.  For linear algebra types, for instance,
 many C++ libraries will provide typedefs for the most common
 combinations of floating point type and number of components, maybe a
 dozen or so of these.

This begs the question, will

<voice=Inigo Montoya> You keep using that phrase. I do not think it means what you think it means.</voice>
     enum SomeTemplate!(int) x;
 
 instantiate the template if x is not used?

There's definitely something needing explaining here. On the one hand new enum is supposed to be just like old enum expanded (no storage just a #define basically), and on the other its supposed to be like D2's current const storage class. --bb
Dec 09 2007
prev sibling next sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Janice Caron wrote:
 On 12/9/07, Stewart Gordon <smjg_1998 yahoo.com> wrote:
 I think constness template
 parameters (defined as a special case that generates only one instantiation)
 would be a good way to go - this would also make it possible to parameterize
 something on the constness of more than one entity.  How about

     K(T)* ptr(constness K : this)() { return a.ptr }

I /like/ this! Please can we have this syntax? (Except of course, the word is "constancy", not "constness". There's no such word as "constness".) For functions whose input constancy is derived from a parameter other than "this", one could write K(T)* f(constancy K)(K(T)[] a) { return a.ptr; } This is clearly much better than using any reserved word. Plus, the compiler knows to generate exactly one instantiation, with exactly three APIs.

Agreed, I really like this idea.
Dec 09 2007
prev sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Janice Caron wrote:
 No, sorry - I figured out the problem. Invariant classes and invariant
 member functions make no sense. This was discussed in another thread
 somewhere, and Walter agreed.

Link? More than half of the classes I write are invariant after construction, and having the compiler be able to optimize that would be great (Java 6's HotSpot can, after all, without any special marking in the code).
Dec 09 2007
parent =?ISO-8859-1?Q?S=F6nke_Ludwig?= writes:
Janice Caron wrote:
 On 12/9/07, Robert Fraser <fraserofthenight gmail.com> wrote:
 Janice Caron wrote:
 No, sorry - I figured out the problem. Invariant classes and invariant
 member functions make no sense. This was discussed in another thread
 somewhere, and Walter agreed.

construction, and having the compiler be able to optimize that would be great (Java 6's HotSpot can, after all, without any special marking in the code).

Sorry, I can't remember, but just ask Walter for his current opinion (and if it's different from his previous opinion, so be it). Basically, it boils down to the fact that invariant C = new C; won't compile, because mutable won't implicitly convert to invariant. For that, you'd need Walter to add a language construct like invariant C = inew C; ...which of course doesn't exist. I know you could always write invariant C = cast(invariant(C)) new C; but casts are a last resort, as they're error-prone. Assuming we decide we /do/ have to support invariant classes after all, then the compiler was correct to flag the error that it did. The line in question was
         invariant(T)* ptr() invariant { return a.ptr; }



and that error arises because T* (the type of a.ptr) will not implicitly convert to invariant(T)*. If you really wanted to support invariant classes, that line would have to be changed to: invariant(T)* ptr() invariant { return cast(invariant(T)*) a.ptr; } Simply put - invariant classes lead to lots of casting. And they're pointless anyway, because Walter said (...and I'm sorry, I can't find you a link, but I'm sure he'll read this and correct me if I'm wrong...) that invariant classes don't help with optimization anyway, so why bother with them?

I have actually changed a bunch of classes to be invariant, that is, they are declared as "invariant class C {}". At least, if they are used like this, no extra casts are necessary. "new C" works, and inside of the class nothing needs to be manually declared invariant using a cast. The main benefit here is not compiler optimization, but by knowing some instance is invariant, you can use this instance from any number of threads without worrying about locking/synchronization. I think this can sometimes be a very useful feature to enforce instance invariantness in the language (and to document it at the same time).
Dec 09 2007
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 Janice Caron wrote:
 I know there was a suggestion in the Walter/Andrei document, but has
 it been finalised?

 I'm referring to the ability to define the constancy/invariance of the
 return type in terms of the constancy/invariance of a calling
 parameter, in order to avoid having to write the same function three
 times.

That can now be done with a template.

I was hoping the return thing would let us define virtual methods. A template solution won't allow that currently. Is there a plan to change that? --bb
Dec 07 2007
parent Walter Bright <newshound1 digitalmars.com> writes:
Bill Baxter wrote:
 I was hoping the return thing would let us define virtual methods.  A 
 template solution won't allow that currently.  Is there a plan to change 
 that?

Not at the moment.
Dec 07 2007
prev sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
Janice Caron wrote:
 On 12/7/07, Walter Bright <newshound1 digitalmars.com> wrote:
 That can now be done with a template.

Not if we're talking virtual member functions, it can't.

I dislike that limitation of virtual methods and templates, but I don't see a clean and efficient way around it. I should spend a couple years working on it and then publish a paper on the topic, and then submit a patch to bugzilla based on the work.
Dec 07 2007
parent Christopher Wright <dhasenan gmail.com> writes:
Christopher Wright wrote:
 Janice Caron wrote:
 On 12/7/07, Walter Bright <newshound1 digitalmars.com> wrote:
 That can now be done with a template.

Not if we're talking virtual member functions, it can't.

I dislike that limitation of virtual methods and templates, but I don't see a clean and efficient way around it. I should spend a couple years working on it and then publish a paper on the topic, and then submit a patch to bugzilla based on the work.

Okay, it actually isn't that hard, I think, as long as you compile your entire application in one go. Or at least, the compiler has to have it all available at once. You don't need to send anything up the inheritance tree, but you do need to send stuff down. You'd need to get a list, for each templated method, of each instantiation; then, for each class that inherits from the base class, you'd have to adjust the vtbl appropriately. I'm not sure how templated methods work currently -- you can have an arbitrary number of instantiations for an arbitrary number of templates in a class, and those all affect the vtbl, and they have to do so in some predictable manner. Unless you make them into global functions that have the same call style as regular methods rather than putting them into the vtbl, which seems the easiest route, you have to compile the entire application in one go. This is not the current case, so I conclude that templated methods are free methods that take a this pointer. (And it's probably been mentioned here.) The vtbl is one of the main reasons that you get fast virtual method calls: one pointer dereference to get to the vtbl, one addition and a dereference to get to the method. In order to get virtual templated methods, you could use that idea, but in order to use a plain list, you'd need to fill in the vtbl at link time. That isn't actually hard, in theory, but you need a custom linker -- or more likely, add in a prelink phase to compilation just for this. Or, you could keep a special object file (or some other convenient format) somewhere for virtual templated methods. If you kept all results from template expansion there, it'd solve the problem of multiple instantiation, too. However, this also involves parsing object files -- or some other intermediate format. And it increases the size of the resulting binaries if you're compiling for multiple projects. And it does some nasty things with order of compilation with revisions, probably. And it disallows building in parallel, without some locking mechanism on the templates file. (You'd have to recompile all modules which contain classes that derive from the one with the updated list of virtual template instantiations, but that's normal, since you're effectively recompiling a module they import.) So, the method's not terribly complex, I think, but it'd be extremely annoying to work with. At the very least, you'd want template methods to be final by default so most people could ignore the whole issue.
Dec 08 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/7/07, Walter Bright <newshound1 digitalmars.com> wrote:
 That can now be done with a template.

Not if we're talking virtual member functions, it can't.
Dec 07 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/7/07, Jason House <jason.james.house gmail.com> wrote:
 That can now be done with a template.

Does that mean the return keyword affecting an input parameter won't ever be implemented? IMHO, the return keyword is more elegant than using templates.

Maybe I'm being a bit dumb here, but I just don't seem to be able to figure out how templates will help. Here's a typical problem. class MyArray(T) { T[] a; T* ptr() { return a.ptr; } const(T)* ptr() const { return a.ptr; } invariant(T)* ptr() invariant { return a.ptr; } } A template helps how, exactly?
Dec 07 2007
prev sibling next sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 12/8/07, Walter Bright <newshound1 digitalmars.com> wrote:
 Janice Caron wrote:
 Here's a typical problem.

     class MyArray(T)
     {
         T[] a;

         T* ptr() { return a.ptr; }
         const(T)* ptr() const { return a.ptr; }
         invariant(T)* ptr() invariant { return a.ptr; }
     }

 A template helps how, exactly?

TransferConst!(U,T) ptr(this U)() { return a.ptr; }

There are several things I don't understand about this example. You seem to be suggesting that TransferConst!(U,T) resolves to K(T)* where K stands for const, invariant or nothing. That's not obvious to me, but I'll believe you. But suppose instead I had wanted a return type of K(T)[], or K(T)[int]? What then? Where is the return type? I am very confused. The next thing I don't understand is the notation ptr(this U)() How does that even parse? I'm not familiar with this means of specifying template parameters. What does it mean? The third thing I don't understand is, I see no specication of the constancy of the member function itself. I expect to see either const-at-the-end, or const-at-the-start, but I see neither. Where is it? And of course, my final question has to be, is this function still virtual? Because if it's not, I'll just carry on writing functions the old way. Cut and paste isn't /that/ bad. Let's apply the readability test now. Which is more readable? First, the current way: T* ptr() { return a.ptr; } const(T)* ptr() const { return a.ptr; } invariant(T)* ptr() invariant { return a.ptr; } Next, the way Walter suggested TransferConst!(U,T) ptr(this U)() { return a.ptr; } Next, my suggestion - replace "const" with some other symbol (here I shall write "K"), and write the function exactly once. K(T)* ptr() K { return a.ptr; } ...or, in const-at-the-front notation K K(T)* ptr() { return a.ptr } ...or, with our proposed const(this) syntax: K(this) K(T)* ptr() { return a.ptr } I think my way looks most readable, but you tell me. I don't actually care what the replacement symbol is. Obviously, "K" is an unwise choice, but you could use any reserved word (I believe "return" was suggested in your document), or even some combination of reserved words like "const in" and "const out", or whatever. (And I'd also like the symbol to be available within the body of the function). One really important point to consider is that you need EXACTLY ONE instantiation of the function. That is, the bytes of machine code which comprise the function would be identical in all three cases, and therefore need to exist only once. I suspect that your template idea, in addition to robbing me of virtuality, would also instantiate the function three times.
Dec 08 2007
parent "Stewart Gordon" <smjg_1998 yahoo.com> writes:
"Janice Caron" <caron800 googlemail.com> wrote in message
news:mailman.263.1197106829.2338.digitalmars-d puremagic.com...
 On 12/8/07, Walter Bright <newshound1 digitalmars.com> wrote:
 Janice Caron wrote:
 Here's a typical problem.

     class MyArray(T)
     {
         T[] a;

         T* ptr() { return a.ptr; }
         const(T)* ptr() const { return a.ptr; }
         invariant(T)* ptr() invariant { return a.ptr; }
     }



This doesn't work for me. Add any one (or more) of MyArray!(int) a; const(MyArray!(int)) c; invariant(MyArray!(int)) i; and I get (DMD 2.008) transfer_const.d(7): Error: cannot implicitly convert expression (cast(int*)(this.a)) of type int* to invariant(int)*
 A template helps how, exactly?

TransferConst!(U,T) ptr(this U)() { return a.ptr; }

There are several things I don't understand about this example. You seem to be suggesting that TransferConst!(U,T)

It doesn't seem to exist, according to a search through the DMD and Phobos code. <snip>
 The next thing I don't understand is the notation

    ptr(this U)()

http://www.digitalmars.com/d/template.html#TemplateThisParameter However, it crashes DMD when I try to use it in a class member function. Need to investigate....
 How does that even parse? I'm not familiar with this means of
 specifying template parameters. What does it mean?

 The third thing I don't understand is, I see no specication of the
 constancy of the member function itself. I expect to see either
 const-at-the-end, or const-at-the-start, but I see neither. Where is
 it?

In the aforementioned (this U), I think. <snip>
    K(this) K(T)* ptr() { return a.ptr }

 I think my way looks most readable, but you tell me. I don't actually
 care what the replacement symbol is. Obviously, "K" is an unwise
 choice, but you could use any reserved word (I believe "return" was
 suggested in your document), or even some combination of reserved
 words like "const in" and "const out", or whatever. (And I'd also like
 the symbol to be available within the body of the function).

"return" doesn't seem to make any sense. I think constness template parameters (defined as a special case that generates only one instantiation) would be a good way to go - this would also make it possible to parameterize something on the constness of more than one entity. How about K(T)* ptr(constness K : this)() { return a.ptr }
 One really important point to consider is that you need EXACTLY ONE
 instantiation of the function. That is, the bytes of machine code
 which comprise the function would be identical in all three cases, and
 therefore need to exist only once. I suspect that your template idea,
 in addition to robbing me of virtuality, would also instantiate the
 function three times.

I've a vague recollection of reading somewhere that templates that differ only in constness are already defined to reduce to a single instance, but I can't seem to find it at the moment. But really, because of the possibility of bits of code being conditional on constness, we need to have both options available somehow. Stewart. -- My e-mail address is valid but not my primary mailbox. Please keep replies on the 'group where everybody may benefit.
Dec 08 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/8/07, Janice Caron <caron800 googlemail.com> wrote:
 One really important point to consider is that you need EXACTLY ONE
 instantiation of the function. That is, the bytes of machine code
 which comprise the function would be identical in all three cases, and
 therefore need to exist only once. I suspect that your template idea,
 in addition to robbing me of virtuality, would also instantiate the
 function three times.

This is really key for me. A member function like K(T)[] f() { /*...*/ } K where K stands for const, invariant, or nothing, needs exactly one instantiation, not three, though it may generate three distinct APIs. Also, there's no reason why it can't be virtual. Templates would not only generate three distinct instantiations, they would rob us of of virtuality. Let's go back to the array example. I could write a /single/ function class MyArray(T) { T[] a; const(T)* ptr() const { return a.ptr; } } with the knowledge that I could safely do MyArray!(int) a; int* ptr = cast(int*)a.ptr; because I have a priori knowledge that a is not const. It should be possible to encapsulate that knowledge in the function definition.
Dec 08 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
But I think there's still a problem. If I write

    class MyArray(T)
    {
        T[] a;
        TransferConst!(U,T*) ptr(this U)()
        {
            return a.ptr;
        }
    }

    const MyArray!(int) aa;
    auto p = aa.ptr;

Then presumably it won't compile, becase aa is not mutable, and
therefore cannot call a member function which has not been declared
const. To make it compile, I'd have to change it to

    class MyArray(T)
    {
        T[] a;
        TransferConst!(U,T*) ptr(this U)() const
        {
            return a.ptr;
        }
    }

But doesn't that now mean that "this" will /always/ be const within
that function? Hence, if I now do

    MyArray!(int) aa;
    auto p = aa.ptr;

won't the type of p end up being const(int)[] rather than int[] ?
Dec 08 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/9/07, Stewart Gordon <smjg_1998 yahoo.com> wrote:
 I think constness template
 parameters (defined as a special case that generates only one instantiation)
 would be a good way to go - this would also make it possible to parameterize
 something on the constness of more than one entity.  How about

     K(T)* ptr(constness K : this)() { return a.ptr }

I /like/ this! Please can we have this syntax? (Except of course, the word is "constancy", not "constness". There's no such word as "constness".) For functions whose input constancy is derived from a parameter other than "this", one could write K(T)* f(constancy K)(K(T)[] a) { return a.ptr; } This is clearly much better than using any reserved word. Plus, the compiler knows to generate exactly one instantiation, with exactly three APIs.
Dec 09 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/9/07, Stewart Gordon <smjg_1998 yahoo.com> wrote:
 Here's a typical problem.

     class MyArray(T)
     {
         T[] a;

         T* ptr() { return a.ptr; }
         const(T)* ptr() const { return a.ptr; }
         invariant(T)* ptr() invariant { return a.ptr; }
     }



This doesn't work for me. Add any one (or more) of MyArray!(int) a; const(MyArray!(int)) c; invariant(MyArray!(int)) i; and I get (DMD 2.008) transfer_const.d(7): Error: cannot implicitly convert expression (cast(int*)(this.a)) of type int* to invariant(int)*

Yep, sorry. It should be class MyArray(T:T) Walter changed the syntax between D2.007 and D2.008. Constancy of template parameters is now thrown away unless you do T:T.
Dec 09 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/9/07, Janice Caron <caron800 googlemail.com> wrote:
 transfer_const.d(7): Error: cannot implicitly convert expression
 (cast(int*)(this.a)) of type int* to invariant(int)*

Yep, sorry. It should be

No, sorry - I figured out the problem. Invariant classes and invariant member functions make no sense. This was discussed in another thread somewhere, and Walter agreed. So in fact, you only have to consider the const and non-const instantiations. You can forget the invariant one. So, in fact, you only need class MyArray(T) { T[] a; T* ptr() { return a.ptr; } const(T)* ptr() const { return a.ptr; } }
Dec 09 2007
prev sibling next sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 12/9/07, Robert Fraser <fraserofthenight gmail.com> wrote:
 Agreed, I really like this idea.

Also, you wouldn't really have to invent a new keyword! Neither "constness" nor "constancy" is needed, because we could instead maybe do (const : K) or something. Maybe even (const K) would work?
Dec 09 2007
parent "Stewart Gordon" <smjg_1998 yahoo.com> writes:
"Janice Caron" <caron800 googlemail.com> wrote in message 
news:mailman.285.1197189662.2338.digitalmars-d puremagic.com...
 On 12/9/07, Robert Fraser <fraserofthenight gmail.com> wrote:
 Agreed, I really like this idea.

Also, you wouldn't really have to invent a new keyword! Neither "constness" nor "constancy" is needed, because we could instead maybe do (const : K) or something. Maybe even (const K) would work?

(const : K) - confusing. Looks too much like a specialization. (const K) - possibly ambiguous, and even if not, still confusing. Looks like it means 'an arbitrary type K, modified to be const'. Stewart. -- My e-mail address is valid but not my primary mailbox. Please keep replies on the 'group where everybody may benefit.
Dec 09 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/9/07, Robert Fraser <fraserofthenight gmail.com> wrote:
 Janice Caron wrote:
 No, sorry - I figured out the problem. Invariant classes and invariant
 member functions make no sense. This was discussed in another thread
 somewhere, and Walter agreed.

Link? More than half of the classes I write are invariant after construction, and having the compiler be able to optimize that would be great (Java 6's HotSpot can, after all, without any special marking in the code).

Sorry, I can't remember, but just ask Walter for his current opinion (and if it's different from his previous opinion, so be it). Basically, it boils down to the fact that invariant C = new C; won't compile, because mutable won't implicitly convert to invariant. For that, you'd need Walter to add a language construct like invariant C = inew C; ...which of course doesn't exist. I know you could always write invariant C = cast(invariant(C)) new C; but casts are a last resort, as they're error-prone. Assuming we decide we /do/ have to support invariant classes after all, then the compiler was correct to flag the error that it did. The line in question was
         invariant(T)* ptr() invariant { return a.ptr; }



and that error arises because T* (the type of a.ptr) will not implicitly convert to invariant(T)*. If you really wanted to support invariant classes, that line would have to be changed to: invariant(T)* ptr() invariant { return cast(invariant(T)*) a.ptr; } Simply put - invariant classes lead to lots of casting. And they're pointless anyway, because Walter said (...and I'm sorry, I can't find you a link, but I'm sure he'll read this and correct me if I'm wrong...) that invariant classes don't help with optimization anyway, so why bother with them?
Dec 09 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/9/07, Walter Bright <newshound1 digitalmars.com> wrote:
 Janice Caron wrote:
 But I think there's still a problem. If I write

     class MyArray(T)
     {
         T[] a;
         TransferConst!(U,T*) ptr(this U)()
         {
             return a.ptr;
         }
     }

     const MyArray!(int) aa;
     auto p = aa.ptr;

 Then presumably it won't compile, becase aa is not mutable,

Template member functions are not instantiated until they are called.

I'm calling it! I'm calling it! See that line that says "auto p = aa.ptr"? That (attempts to) call MyArray!(int).ptr(). However - as I said - presumably it won't compile because aa is const, and the function ptr(this U)() has not been declared as const. So there's a problem. How may this problem be fixed?
Dec 09 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
It's no good. I just can't figure it out. Let me state a (not
uncommon) problem. See this code:

    class A
    {
        int[] a;
        this() { a.length = 4; }

        /* K K(int)* p() { return a.ptr } */
    }

    A m = new A;
    const A c = new A;
    invariant A i = cast(invariant)new A;

    int* mp = m.p();
    ++mp;
    const(int)* cp = c.p();
    ++cp;
    invariant(int)* ip = i.p();
    ++ip;

Your task is to repace the comment inside class A, with real code,
which has the effect of replacing K by "const", "invariant" or
nothing. (That is, it must, in each case, return the address of a[0]).
The result must compile.

For the life of me, I cannot figure out how to do it. Your
TransferConst! template doesn't seem to be powerful enough to do the
job; I can't overload on the constancy of this ... I'm stuck!

What's the answer?
Dec 09 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/9/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:
 The instatiate-if-aliased behavior of D is a little annoying because it
 means you can't create convenience aliases of your templates without
 bloating up your executable.  For linear algebra types, for instance,
 many C++ libraries will provide typedefs for the most common
 combinations of floating point type and number of components, maybe a
 dozen or so of these.

This begs the question, will enum SomeTemplate!(int) x; instantiate the template if x is not used?
Dec 09 2007
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 12/9/07, Janice Caron <caron800 googlemail.com> wrote:
 This begs the question, will

     enum SomeTemplate!(int) x;

Sorry. I meant enum SomeTemplate!(int) x = something;
 instantiate the template if x is not used?

(It'll take a while to get used to this).
Dec 09 2007
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On Dec 9, 2007 11:36 PM, Sönke Ludwig
<ludwig informatik_dot_uni-luebeck.de> wrote:
 I have actually changed a bunch of classes to be invariant, that is, they are
 declared as "invariant class C {}". At least, if they are used like this, no
 extra casts are necessary. "new C" works, and inside of the class nothing needs
 to be manually declared invariant using a cast.

Wow! I didn't know you could do that! That's actually a pretty cool feature! OK, so there /is/ language support. That means I was wrong, and you can forget everything I ever said about invariant classes.
Dec 09 2007