www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Reuse of variables referencing const objects

reply Sergey Kovrov <kovrov+digitalmars gmail.com> writes:
I wonder if it is possible to reuse a variable for a const/invariant reference
type? By "reuse" I mean to reference different data. Considering code:

  auto f = new const(Foo)();  // Foo is a class, e.g. reference type
  f = new Foo();  // error: cannot modify const

But here I really meant to assign new data to variable `f`, not to modify old
instance.

Of course, I could use mutable pointer to const/invariant data. But this make
sense only for value types. In case of reference types this will complicate
things (introducing more human errors) and just feels wrong. Consider code:

  const (Foo)* foo = a_condition ? &some_foo : null;
  if (foo !is null && *foo !is null)
      ...;

Reference types was invented to simplify things. And they do, but not in case
of const data. Do I miss something, or const support in reference types is not
there yet?

-- serg.
Mar 06 2009
parent reply Sergey Kovrov <kovrov+digitalmars gmail.com> writes:
Other reference types (e.g. arrays) have solution to this:
``immutable(TYPE)[]`` and ``immutable(TYPE[])`.

I think class instances should have something similar in language as well.


-- serg.
Mar 06 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Sergey Kovrov:

 Other reference types (e.g. arrays)<
Arrays aren't really references, they are a small 2-word long struct, that contains a pointer to the data and a length. Bye, bearophile
Mar 06 2009
parent reply Sergey Kovrov <kovrov+digitalmars gmail.com> writes:
On 3/6/2009 4:42 PM, bearophile wrote:
 Arrays aren't really references, they are a small 2-word long struct,
 that contains a pointer to the data and a length.
I guess there is a data member for allocated buffer size as well... Objects may be viewed as a structure too. There are context pointer virtual function table and maybe something else implementation-specific. -- serg.
Mar 06 2009
parent bearophile <bearophileHUGS lycos.com> writes:
Sergey Kovrov:
 I guess there is a data member for allocated buffer size as well...
Nope, this isn't vector of C++. It's a long story (caused to allow the slicing). The result is that the append is very slow.
 Objects may be viewed as a structure too. There are context pointer 
 virtual function table and maybe something else implementation-specific.
Objects are managed by a reference (even in a transparent way, when you use scope and the compiler accepts it). Bye, bearophile
Mar 06 2009
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On Fri, 06 Mar 2009 09:39:43 -0500, Sergey Kovrov wrote:

 Other reference types (e.g. arrays) have solution to this:
 ``immutable(TYPE)[]`` and ``immutable(TYPE[])`.
 
 I think class instances should have something similar in language as
 well.
 
 
 -- serg.
std.typecons.Rebindable http://www.digitalmars.com/d/2.0/phobos/std_typecons.html#Rebindable -Steve
Mar 06 2009
parent reply Sergey Kovrov <kovrov+digitalmars gmail.com> writes:
On 3/6/2009 11:29 PM, Steven Schveighoffer wrote:
 std.typecons.Rebindable

 http://www.digitalmars.com/d/2.0/phobos/std_typecons.html#Rebindable
Thanks Steve, this is what I've been looking for, the only thing missing is comparing against null (is null). -- serg.
Mar 07 2009
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Sergey Kovrov wrote:
 On 3/6/2009 11:29 PM, Steven Schveighoffer wrote:
 std.typecons.Rebindable

 http://www.digitalmars.com/d/2.0/phobos/std_typecons.html#Rebindable
Thanks Steve, this is what I've been looking for, the only thing missing is comparing against null (is null). -- serg.
While not strictly intuitive, you could do this: auto var = Rebindable!(const Foo)(new Foo); assert(var.opDot !is null); As 'opDot' returns the wrapped object (with const intact). The downside to that, however, is that it won't work in those cases where Rebindable's template parameter was mutable, as then it simply aliases it. This shouldn't be a problem in general use, though. Only in generic code, which could try to check for Rebindable. -- Christopher Nicholson-Sauls
Mar 09 2009
parent reply Sergey Kovrov <kovrov+digitalmars gmail.com> writes:
On 3/9/2009 8:50 PM, Chris Nicholson-Sauls wrote:
 While not strictly intuitive, you could do this:
 auto var = Rebindable!(const Foo)(new Foo);
 assert(var.opDot !is null);

 As 'opDot' returns the wrapped object (with const intact). The downside
 to that, however, is that it won't work in those cases where
 Rebindable's template parameter was mutable, as then it simply aliases
 it. This shouldn't be a problem in general use, though. Only in generic
 code, which could try to check for Rebindable.
Thanks Chris, this approach indeed works, its a shame I haven't figured this on my own. I wonder if it's proper usage of opDot.. In general, is it safe for client code to rely on implementation of opDot and call it directly? And in this particular case we rely on the fact that Rebindable uses opDot to forward calls. Slightly off-topic... In Python world (and I guess any other dynamic language) it is not valid to make assumptions based on implementation. Only safe way to use "foreign code" (a library, framework) is to follow documentation. That way authors of libraries are free to change their code as long as it comply with documented behavior. -- serg.
Mar 09 2009
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Sergey Kovrov wrote:
 On 3/9/2009 8:50 PM, Chris Nicholson-Sauls wrote:
 While not strictly intuitive, you could do this:
 auto var = Rebindable!(const Foo)(new Foo);
 assert(var.opDot !is null);

 As 'opDot' returns the wrapped object (with const intact). The downside
 to that, however, is that it won't work in those cases where
 Rebindable's template parameter was mutable, as then it simply aliases
 it. This shouldn't be a problem in general use, though. Only in generic
 code, which could try to check for Rebindable.
Thanks Chris, this approach indeed works, its a shame I haven't figured this on my own. I wonder if it's proper usage of opDot.. In general, is it safe for client code to rely on implementation of opDot and call it directly?
Technically, no, not really. Then again, it isn't absolutely horrible either. It would be better if there were some other means of testing for null, which could be overwritten. The only alternative that comes immediately to mind would be an opCast to T, but then it would supersede any opCast defined on T. (Then again, in code dealing with Rebindable one could always chain the casts: 'cast(Bar)cast(Foo)var'. Ugly, but possibly effective.
 And in this particular case we rely on the fact that Rebindable uses 
 opDot to forward calls.
Considering its the only way of doing so in a completely generic manner anyhow, I don't think its a big deal. It could become annoying, however, for generic code.
 Slightly off-topic... In Python world (and I guess any other dynamic 
 language) it is not valid to make assumptions based on implementation. 
 Only safe way to use "foreign code" (a library, framework) is to follow 
 documentation. That way authors of libraries are free to change their 
 code as long as it comply with documented behavior.
 
 
 -- serg.
The sentiment applies in almost any language, but a static typed language does allow for a few more assumptions. I have a habit of crawling through the sources of libraries I use anyhow, so I'm sure I occasionally do things in "*evil*" undocumented ways. ;) Maybe there should be an 'IsNull' template that understands Rebindable's. That said, I'm not sure what kind of is() invocation would match a struct template... (pssst, template ninjas...) -- Chris Nicholson-Sauls
Mar 09 2009
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 09 Mar 2009 23:00:50 -0400, Chris Nicholson-Sauls wrote:

 Sergey Kovrov wrote:
 On 3/9/2009 8:50 PM, Chris Nicholson-Sauls wrote:
 While not strictly intuitive, you could do this:
 auto var = Rebindable!(const Foo)(new Foo);
 assert(var.opDot !is null);

 As 'opDot' returns the wrapped object (with const intact). The downside
 to that, however, is that it won't work in those cases where
 Rebindable's template parameter was mutable, as then it simply aliases
 it. This shouldn't be a problem in general use, though. Only in generic
 code, which could try to check for Rebindable.
Thanks Chris, this approach indeed works, its a shame I haven't figured this on my own. I wonder if it's proper usage of opDot.. In general, is it safe for client code to rely on implementation of opDot and call it directly?
Technically, no, not really. Then again, it isn't absolutely horrible either. It would be better if there were some other means of testing for null, which could be overwritten. The only alternative that comes immediately to mind would be an opCast to T, but then it would supersede any opCast defined on T. (Then again, in code dealing with Rebindable one could always chain the casts: 'cast(Bar)cast(Foo)var'. Ugly, but possibly effective.
 And in this particular case we rely on the fact that Rebindable uses  
 opDot to forward calls.
Considering its the only way of doing so in a completely generic manner anyhow, I don't think its a big deal. It could become annoying, however, for generic code.
 Slightly off-topic... In Python world (and I guess any other dynamic  
 language) it is not valid to make assumptions based on implementation.  
 Only safe way to use "foreign code" (a library, framework) is to follow  
 documentation. That way authors of libraries are free to change their  
 code as long as it comply with documented behavior.
   -- serg.
The sentiment applies in almost any language, but a static typed language does allow for a few more assumptions. I have a habit of crawling through the sources of libraries I use anyhow, so I'm sure I occasionally do things in "*evil*" undocumented ways. ;) Maybe there should be an 'IsNull' template that understands Rebindable's. That said, I'm not sure what kind of is() invocation would match a struct template... (pssst, template ninjas...)
The "is null" construct is pretty special to the compiler, it avoids calling any methods of any kind, and simply does a bit compare. I'm not sure if implicit casting is used. What would also work is this: auto var = Rebindable!(const Foo)(new Foo); assert(var !is var.init); // or assert(var !is typeof(var)(null)); Personally, I think the compiler should recognize the "struct with opDot" form, and translate var is null to var.opDot is null automatically. Or at least translate to something like the latter form, where it tries to construct a type using null. Why not file an enhancment request? -Steve
Mar 10 2009