digitalmars.D.learn - Frustrations with const
- H. S. Teoh (26/26) Mar 08 2012 I'm writing an AA implementation, and ran into this problem with the way
- Timon Gehr (2/26) Mar 08 2012 inout(Slot)* findSlot(Key key) inout { ... }
- H. S. Teoh (18/36) Mar 08 2012 [...]
- Steven Schveighoffer (6/41) Mar 08 2012 What is type slot, and how is it constructed? This snippit isn't enough...
- H. S. Teoh (14/29) Mar 08 2012 [...]
- Steven Schveighoffer (10/36) Mar 08 2012 I was wondering, because your error message identified it as inout(Slot)...
- Timon Gehr (5/32) Mar 09 2012 This is a general issue with how auto infers types. It would often be
- H. S. Teoh (29/51) Mar 09 2012 Here are the relevant declarations:
- Adam D. Ruppe (6/7) Mar 09 2012 I think it was actually decided to do that... they
- H. S. Teoh (10/13) Mar 09 2012 Oh really? I don't think I changed any settings related to that. AFAICT
- Timon Gehr (2/36) Mar 08 2012
I'm writing an AA implementation, and ran into this problem with the way const behaves in D. Basically, I have an auxiliary function that searches the internal hash table for a given key, and returns the slot containing the matching entry, if found. The problem is, how to write this function so that it can be called from *both* a const public method and a non-const public method? Since the method itself doesn't actually modify anything, it *should* in theory be possible to mark it as const: const Slot *findSlot(Key key) { ... } However, because the const applies to 'this', the compiler insists that referencing anything via 'this', including reading a pointer to a slot, must also be const, so it refuses to let the return type be Slot*; it has to be const(Slot)*. But this is silly, because now the caller isn't allowed to modify the Slot either, so now I need to bloat the code with two identical copies of findSlot, one with const, and one without (since if it wasn't marked const, then a const method couldn't call it). Is there any way to work around this? Or more importantly, why does the compiler force all internal members of this to be const inside a const method, when what it really should be enforcing is that nothing is being *modified*? What's wrong with extracting non-const members from the object in a const method, if you never actually do anything to it? T -- Never wrestle a pig. You both get covered in mud, and the pig likes it.
Mar 08 2012
On 03/08/2012 08:09 PM, H. S. Teoh wrote:I'm writing an AA implementation, and ran into this problem with the way const behaves in D. Basically, I have an auxiliary function that searches the internal hash table for a given key, and returns the slot containing the matching entry, if found. The problem is, how to write this function so that it can be called from *both* a const public method and a non-const public method? Since the method itself doesn't actually modify anything, it *should* in theory be possible to mark it as const: const Slot *findSlot(Key key) { ... } However, because the const applies to 'this', the compiler insists that referencing anything via 'this', including reading a pointer to a slot, must also be const, so it refuses to let the return type be Slot*; it has to be const(Slot)*. But this is silly, because now the caller isn't allowed to modify the Slot either, so now I need to bloat the code with two identical copies of findSlot, one with const, and one without (since if it wasn't marked const, then a const method couldn't call it). Is there any way to work around this? Or more importantly, why does the compiler force all internal members of this to be const inside a const method, when what it really should be enforcing is that nothing is being *modified*? What's wrong with extracting non-const members from the object in a const method, if you never actually do anything to it? Tinout(Slot)* findSlot(Key key) inout { ... }
Mar 08 2012
On Thu, Mar 08, 2012 at 08:22:05PM +0100, Timon Gehr wrote:On 03/08/2012 08:09 PM, H. S. Teoh wrote:[...][...]The problem is, how to write this function so that it can be called from *both* a const public method and a non-const public method? Since the method itself doesn't actually modify anything, it *should* in theory be possible to mark it as const: const Slot *findSlot(Key key) { ... } However, because the const applies to 'this', the compiler insists that referencing anything via 'this', including reading a pointer to a slot, must also be const, so it refuses to let the return type be Slot*; it has to be const(Slot)*. But this is silly, because now the caller isn't allowed to modify the Slot either, so now I need to bloat the code with two identical copies of findSlot, one with const, and one without (since if it wasn't marked const, then a const method couldn't call it).inout(Slot)* findSlot(Key key) inout { ... }Ahhh. Thanks! But that still doesn't solve the problem: inout(Slot)* findSlot(Key key) inout { auto slot = slots[hash(key)]; while (slot) { if (slot.hash == hash(key) && slot.key == key) return slot; // Error: cannot modify inout(Slot)* ---> slot = slot.next; } return null; } T -- Help a man when he is in trouble and he will remember you when he is in trouble again.
Mar 08 2012
On Thu, 08 Mar 2012 14:49:12 -0500, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:On Thu, Mar 08, 2012 at 08:22:05PM +0100, Timon Gehr wrote:What is type slot, and how is it constructed? This snippit isn't enough to provide help.On 03/08/2012 08:09 PM, H. S. Teoh wrote:[...][...]The problem is, how to write this function so that it can be calledfrom*both* a const public method and a non-const public method? Since the method itself doesn't actually modify anything, it *should* in theorybepossible to mark it as const: const Slot *findSlot(Key key) { ... } However, because the const applies to 'this', the compiler insists that referencing anything via 'this', including reading a pointer to a slot, must also be const, so it refuses to let the return type be Slot*; it has to be const(Slot)*. But this is silly, because now the caller isn't allowed to modify the Slot either, so now I need to bloat the code with two identical copies of findSlot, one with const, and one without (since if it wasn't marked const, then a const method couldn't call it).inout(Slot)* findSlot(Key key) inout { ... }Ahhh. Thanks! But that still doesn't solve the problem: inout(Slot)* findSlot(Key key) inout { auto slot = slots[hash(key)];while (slot) { if (slot.hash == hash(key) && slot.key == key) return slot; // Error: cannot modify inout(Slot)*An exact message is preferrable.---> slot = slot.next; } return null; }-Steve
Mar 08 2012
On Thu, Mar 08, 2012 at 02:50:50PM -0500, Steven Schveighoffer wrote:On Thu, 08 Mar 2012 14:49:12 -0500, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:[...]On Thu, Mar 08, 2012 at 08:22:05PM +0100, Timon Gehr wrote:[...] Slot is a struct, and slots is Slots*[]. But anyway, I found the problem. I needed to explicitly declare slot as: inout(Slot)* slot = ... because for whatever reason, auto turns it into inout(Slot*) which cannot be modified. I think inout is one of those things that really needs more thorough treatment for newbies, because coming from a C/C++ background I had no idea what was wrong. Now that I get it, it makes so much more sense. T -- Life would be easier if I had the source code. -- YHLWhat is type slot, and how is it constructed? This snippit isn't enough to provide help.inout(Slot)* findSlot(Key key) inout { ... }Ahhh. Thanks! But that still doesn't solve the problem: inout(Slot)* findSlot(Key key) inout { auto slot = slots[hash(key)];
Mar 08 2012
On Thu, 08 Mar 2012 15:06:19 -0500, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:On Thu, Mar 08, 2012 at 02:50:50PM -0500, Steven Schveighoffer wrote:I was wondering, because your error message identified it as inout(Slot)*, which should be modifiable...On Thu, 08 Mar 2012 14:49:12 -0500, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:[...]On Thu, Mar 08, 2012 at 08:22:05PM +0100, Timon Gehr wrote:[...] Slot is a struct, and slots is Slots*[]. But anyway, I found the problem. I needed to explicitly declare slot as: inout(Slot)* slot = ... because for whatever reason, auto turns it into inout(Slot*) which cannot be modified.What is type slot, and how is it constructed? This snippit isn't enough to provide help.inout(Slot)* findSlot(Key key) inout { ... }Ahhh. Thanks! But that still doesn't solve the problem: inout(Slot)* findSlot(Key key) inout { auto slot = slots[hash(key)];I think inout is one of those things that really needs more thorough treatment for newbies, because coming from a C/C++ background I had no idea what was wrong. Now that I get it, it makes so much more sense.It's kind of a new concept to D even (since 2.056). It's not completely fleshed out yet, Timon, Kenji, and Stuart have some great ideas on making it better. This article might help: http://drdobbs.com/blogs/cpp/231902461 I plan to write a const/inout article at some point. -Steve
Mar 08 2012
On 03/08/2012 09:06 PM, H. S. Teoh wrote:On Thu, Mar 08, 2012 at 02:50:50PM -0500, Steven Schveighoffer wrote:Probably it does not. What is the type of the "slots" hashtable?On Thu, 08 Mar 2012 14:49:12 -0500, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:[...]On Thu, Mar 08, 2012 at 08:22:05PM +0100, Timon Gehr wrote:[...] Slot is a struct, and slots is Slots*[]. But anyway, I found the problem. I needed to explicitly declare slot as: inout(Slot)* slot = ... because for whatever reason, auto turns it into inout(Slot*) which cannot be modified.What is type slot, and how is it constructed? This snippit isn't enough to provide help.inout(Slot)* findSlot(Key key) inout { ... }Ahhh. Thanks! But that still doesn't solve the problem: inout(Slot)* findSlot(Key key) inout { auto slot = slots[hash(key)];I think inout is one of those things that really needs more thorough treatment for newbies, because coming from a C/C++ background I had no idea what was wrong. Now that I get it, it makes so much more sense. TThis is a general issue with how auto infers types. It would often be useful to get the head-mutable type out of the type deduction instead of the actual type.
Mar 09 2012
On Fri, Mar 09, 2012 at 11:24:46AM +0100, Timon Gehr wrote:On 03/08/2012 09:06 PM, H. S. Teoh wrote:[...]On Thu, Mar 08, 2012 at 02:50:50PM -0500, Steven Schveighoffer wrote:Here are the relevant declarations: struct Slot { Slot *next; hash_t hash; Key key; Value value; this(hash_t h, Key k, Value v) { hash = h; key = k; value = v; } } struct Impl { Slot*[] slots; size_t nodes; // Prevent extra allocations for very small AA's. Slot*[4] binit; } [...]Probably it does not. What is the type of the "slots" hashtable?What is type slot, and how is it constructed? This snippit isn't enough to provide help.[...] Slot is a struct, and slots is Slots*[]. But anyway, I found the problem. I needed to explicitly declare slot as: inout(Slot)* slot = ... because for whatever reason, auto turns it into inout(Slot*) which cannot be modified.[...]I think inout is one of those things that really needs more thorough treatment for newbies, because coming from a C/C++ background I had no idea what was wrong. Now that I get it, it makes so much more sense.This is a general issue with how auto infers types. It would often be useful to get the head-mutable type out of the type deduction instead of the actual type.Yeah, that would be very useful. T -- Tech-savvy: euphemism for nerdy.
Mar 09 2012
On Friday, 9 March 2012 at 15:30:50 UTC, H. S. Teoh wrote:Yeah, that would be very useful.I think it was actually decided to do that... they made the change for templates already. PS: you might want to take a look at your mutt settings. Your replies seem to have a truncated References header which messes up threading in many clients.
Mar 09 2012
On Fri, Mar 09, 2012 at 04:39:13PM +0100, Adam D. Ruppe wrote: [...]PS: you might want to take a look at your mutt settings. Your replies seem to have a truncated References header which messes up threading in many clients.Oh really? I don't think I changed any settings related to that. AFAICT it does generate the right references header. How do I fix it? P.S. I do have mutt set on mailing list mode when replying to this list, though, and I usually reply using 'L'. Does that make a difference? T -- Computerese Irregular Verb Conjugation: I have preferences. You have biases. He/She has prejudices. -- Gene Wirchenko
Mar 09 2012
On 03/08/2012 08:49 PM, H. S. Teoh wrote:On Thu, Mar 08, 2012 at 08:22:05PM +0100, Timon Gehr wrote:inout(Slot)* slot = slots[hash(key)];On 03/08/2012 08:09 PM, H. S. Teoh wrote:[...][...]The problem is, how to write this function so that it can be called from *both* a const public method and a non-const public method? Since the method itself doesn't actually modify anything, it *should* in theory be possible to mark it as const: const Slot *findSlot(Key key) { ... } However, because the const applies to 'this', the compiler insists that referencing anything via 'this', including reading a pointer to a slot, must also be const, so it refuses to let the return type be Slot*; it has to be const(Slot)*. But this is silly, because now the caller isn't allowed to modify the Slot either, so now I need to bloat the code with two identical copies of findSlot, one with const, and one without (since if it wasn't marked const, then a const method couldn't call it).inout(Slot)* findSlot(Key key) inout { ... }Ahhh. Thanks! But that still doesn't solve the problem: inout(Slot)* findSlot(Key key) inout { auto slot = slots[hash(key)];while (slot) { if (slot.hash == hash(key)&& slot.key == key) return slot; // Error: cannot modify inout(Slot)* ---> slot = slot.next; } return null; } T
Mar 08 2012