www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - keywords "objconst" and "objimmutable" vs. const(Object) ref

reply Christopher the Magnificent <ultimatemacfanatic gmail.com> writes:
Greetings all.  First time poster here.

By way of introduction, my name is Christopher.  I've been fascinated 
with D for a few years now.  My main programming language has been 
Python, but I have used and studied many programming languages to some 
extent.  I love to design things, like houses, pipe organs, and even 
computer languages.

What I like about D is that it seems to strike the right balance of 
allowing fairly high level programming with static typing yet still 
permitting access on several progressively deeper levels to the nuts and 
bolts of the computer.  I also love D's module system and its dynamic 
arrays, to name just a few things.

Now down to business.  I want to talk about const and immutable.  There 
are 5,256 posts in this list containing the text "const" so I just this 
topic is discussed often.

We all know that object references are really implemented as pointers to 
the object's data structures on the heap.

When we say "const Object a", we declare a constant variable pointing to 
a constant data structure.  Sometimes we need to declare a modifiable 
variable pointing to a constant data structure.

I propose the syntax "objconst Object a" to declare modifiable reference 
variable pointing to a const object data structure, and "objimmutable 
Object A" for modifiable reference variable pointing to immutable object 
data structure:
	
	objimmutable Object 	a = cast(immutable) new Object();
	objconst Object		b = new Object();

	b = a;	// b is modifiable
	
	// ILLEGAL: b references constant data structure
	b.someVariable = newValue;

These could also be used in the parenthesized way:

	objconst(Object)	a;
	objconst(Object)*[1]	a_array;
	
	a = new Object();
	a_array[0] = &a;
	*a_array[0] = new Object(); // change a to a different object

Now I understand that another syntax has been nominated to do this job 
which is the const(Object)ref syntax.  I dislike that syntax because 
"const(Object)" means a constant variable referencing a constant data 
structure, and "const(Object)ref" LOOKS like it should be a reference to 
a variable of type "const(Object)" -- to me it suggests a variable 
referencing a constant variable referencing a constant data structure. 
"const(Object)ref" suggests TWO levels of pointers, but that is not the 
meaning being ascribed thereunto.

I picked the keywords "objconst" and "objimmutable" to suggest that the 
object data structure (hence the "obj" prefix) is immutable or const. 
This was a compromise between brevity and descriptiveness.  I suppose 
they could also go "constobj" and "immutableobj".

Another reason why the objconst/objimmutable syntax is better than 
"const(Object)ref" is that it requires fewer tokens to parse and to type 
-- this makes it easier to read:

	const(Object) ref 	a; 	// 5 tokens in the type
	objconst Object 	a; 	// only 2 tokens

I submitted this idea to the bug tracking system as a feature request, 
but I also want to hear what people have to say about it on here.

What do you think guys, Mr. Bright?  And what do you like 
better--"objconst" and "objimmutable" or "constobj" and "immutableobj"?

--Christopher
May 17 2011
next sibling parent reply %u <wfunction hotmail.com> writes:
This is what Rebindable(T) is for:

http://www.digitalmars.com/d/2.0/phobos/std_typecons.html
May 17 2011
parent Christopher the Magnificent <ultimatemacfanatic gmail.com> writes:
On 5/17/11 6:17 PM, %u wrote:
 This is what Rebindable(T) is for:

 http://www.digitalmars.com/d/2.0/phobos/std_typecons.html
Thanks for the reference, but to me, rebindable feels like a hack. My opinion is that D deserves to have such an integral feature as mutable references to const object data structures baked into the language with a standard syntax, rather than added on using templates in an imported module. That a rebindable template can implement this functionality at all is a testament to the power and flexibility of D, but this really ought to be a core language feature.
May 17 2011
prev sibling next sibling parent reply Jesse Phillips <jessekphillips+D gmail.com> writes:
Christopher the Magnificent Wrote:

 Greetings all.  First time poster here.
 
 By way of introduction, my name is Christopher.  I've been fascinated 
 with D for a few years now.  My main programming language has been 
 Python, but I have used and studied many programming languages to some 
 extent.  I love to design things, like houses, pipe organs, and even 
 computer languages.
Hello, and welcome.
 Now I understand that another syntax has been nominated to do this job 
 which is the const(Object)ref syntax.  I dislike that syntax because 
 "const(Object)" means a constant variable referencing a constant data 
 structure, and "const(Object)ref" LOOKS like it should be a reference to 
 a variable of type "const(Object)" -- to me it suggests a variable 
 referencing a constant variable referencing a constant data structure. 
 "const(Object)ref" suggests TWO levels of pointers, but that is not the 
 meaning being ascribed thereunto.
Syntax has definitely been a major problem for this feature. Walter's stance has been that he has tried many times to get the semantics and syntax to work and has given up. michelf (Sorry don't know his real name) has created a branch which implements the syntax you are against. As this is a change Walter is skeptical of it will take time to review. Now as for your distaste, I believe the intent is to make a valid declaration: Object ref foobar; Meaning that you are exposing the reference or address itself. However I think there might be more to it when considering generic code which would suggest these should also be valid forms: void function(T)(const(T) ref thing); const(int) ref foo; const(myStruct) ref bar; const(int*) ref bared; But that would suggest D has a reference type, and it doesn't. So in any case, this isn't simple and I'm not really sure how well const(Object) ref stands up to this kind of question.
May 17 2011
next sibling parent reply Christopher the Magnificent <ultimatemacfanatic gmail.com> writes:
On 5/17/11 7:26 PM, Jesse Phillips wrote:
 Christopher the Magnificent Wrote:

 Greetings all.  First time poster here.

 By way of introduction, my name is Christopher.  I've been fascinated
 with D for a few years now.  My main programming language has been
 Python, but I have used and studied many programming languages to some
 extent.  I love to design things, like houses, pipe organs, and even
 computer languages.
Hello, and welcome.
 Now I understand that another syntax has been nominated to do this job
 which is the const(Object)ref syntax.  I dislike that syntax because
 "const(Object)" means a constant variable referencing a constant data
 structure, and "const(Object)ref" LOOKS like it should be a reference to
 a variable of type "const(Object)" -- to me it suggests a variable
 referencing a constant variable referencing a constant data structure.
 "const(Object)ref" suggests TWO levels of pointers, but that is not the
 meaning being ascribed thereunto.
Syntax has definitely been a major problem for this feature. Walter's stance has been that he has tried many times to get the semantics and syntax to work and has given up. michelf (Sorry don't know his real name) has created a branch which implements the syntax you are against. As this is a change Walter is skeptical of it will take time to review. Now as for your distaste, I believe the intent is to make a valid declaration: Object ref foobar; Meaning that you are exposing the reference or address itself. However I think there might be more to it when considering generic code which would suggest these should also be valid forms: void function(T)(const(T) ref thing); const(int) ref foo; const(myStruct) ref bar; const(int*) ref bared; But that would suggest D has a reference type, and it doesn't. So in any case, this isn't simple and I'm not really sure how well const(Object) ref stands up to this kind of question.
Thanks for the background, Jesse Phillips. Do you have any thoughts on my proposed objconst/objimmutable syntax, as to whether you think it is readable, intuitive, and just whether you like it or don't like it?
May 17 2011
parent Jesse Phillips <jessekphillips+D gmail.com> writes:
Christopher the Magnificent Wrote:

 Thanks for the background, Jesse Phillips.  Do you have any thoughts on 
 my proposed objconst/objimmutable syntax, as to whether you think it is 
 readable, intuitive, and just whether you like it or don't like it?
I'm going to go with Michel's reply. The const(Object) ref is more consistent with pointers and the smashed keyword looks weird to me.
May 17 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 17 May 2011 21:26:38 -0400, Jesse Phillips  
<jessekphillips+D gmail.com> wrote:


 Syntax has definitely been a major problem for this feature. Walter's  
 stance has been that he has tried many times to get the semantics and  
 syntax to work and has given up. michelf (Sorry don't know his real  
 name) has created a branch which implements the syntax you are against.  
 As this is a change Walter is skeptical of it will take time to review.
Michel Fortin
 Now as for your distaste, I believe the intent is to make a valid  
 declaration:

 Object ref foobar;

 Meaning that you are exposing the reference or address itself. However I  
 think there might be more to it when considering generic code which  
 would suggest these should also be valid forms:

 void function(T)(const(T) ref thing);

 const(int) ref foo;
 const(myStruct) ref bar;
 const(int*) ref bared;
This doesn't really work, Objects are unique in that they are references under the hood, but they are also rebindable. With an integer reference (i.e. ref int), you cannot rebind the reference. This is as it is in C++ as well. I don't even know how it would work. For instance: int i, j; int ref x = i; // bind the reference to i int ref y = j; x = y; // does this assign to i the value of j, or does it rebind x to be the same as y? I don't think the generic form is really possible. What Michel's proposal does is extract the reference from the data, so you can apply const to just the data and not the reference. It is the single most difficult thing to do in an intuitive way for this problem. This proposal is not the prettiest, and there have been a multitude of attempts to do it (including several by me, I think this is a really important problem to solve). However, his proposal has the distinct advantage that is is *actually implemented* :) So we can try it out and see how it works. I think with the distaste that Walter has towards this problem, this is likely the only way to get him to consider it. So to Christopher, you will likely have to implement any proposal you have in order to get it considered, there is a lot of bad blood between this problem and Walter Bright. -Steve
May 18 2011
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-05-17 20:00:55 -0400, Christopher the Magnificent 
<ultimatemacfanatic gmail.com> said:

 Now I understand that another syntax has been nominated to do this job 
 which is the const(Object)ref syntax.
I don't think there has been any official word on that. But many people have shown support for it.
 I dislike that syntax because "const(Object)" means a constant variable 
 referencing a constant data structure, and "const(Object)ref" LOOKS 
 like it should be a reference to a variable of type "const(Object)" -- 
 to me it suggests a variable referencing a constant variable 
 referencing a constant data structure. "const(Object)ref" suggests TWO 
 levels of pointers, but that is not the meaning being ascribed 
 thereunto.
But ask yourself this: why does "Object ref" looks like a double reference to you? I'll guess an answer: because of previous knowledge of the language that says to you that "Object" is always implicitly a reference type. The basic idea behind the const(Object)ref proposal is to change the meaning of "Object" to become a shortcut for "Object ref". In other word, the "ref" part is always there, and if you omit it, it's added implicitly for you. Try to look at thing from a this new perspective and it'll fit better.
 I picked the keywords "objconst" and "objimmutable" to suggest that the 
 object data structure (hence the "obj" prefix) is immutable or const. 
 This was a compromise between brevity and descriptiveness.  I suppose 
 they could also go "constobj" and "immutableobj".
Personally, I like better the feel of const(Object)ref than any of these keywords. For one thing, it doesn't require any new keyword. For another, it's perfectly in line with how you do it for pointers. Also, it'll work for 'shared' and 'inout' too (once 'inout' works properly). Working like pointers has other advantages too: it allow you to transpose your understanding of type deduction and type matching in templates and is-expressions freely between pointers and objects references. Making the syntax different adds a barrier to applying your experience of one to the other, this barrier simply does not exist with const(Object)ref because the syntax is similar enough to const(S)*.
 Another reason why the objconst/objimmutable syntax is better than 
 "const(Object)ref" is that it requires fewer tokens to parse and to 
 type -- this makes it easier to read:
 
 	const(Object) ref 	a; 	// 5 tokens in the type
 	objconst Object 	a; 	// only 2 tokens
Easier to type, granted. Easier to read, I'm not so sure; mimicking the existing syntax for pointer makes things more coherent. Easier to parse, I'm not too sure about that either, but it's quite irrelevant anyway. What's difficult is implementing the corresponding semantics in the compiler. The main reason being that, unlike the common perception people have, it's only the compiler backend that deals with class types the same way it deals with pointers. Type attributes (const, immutable, shared, inout) are enforced in the frontend, and the frontend has no separate type for an object and an object reference, and thus no way to attach attributes to the reference separately from the main object type. As the entirety of the frontend is written with that assumption in mind, it's hard to overcome without rewriting a very big portion of the code. Now, I figured a way around that, one that Walter will hopefully accept once he find enough time to review my patch. If he thinks another syntax (such as yours) is more appropriate, it should a pretty trivial change. But my preference remains with const(Object)ref. Thanks for your input Christopher, and welcome to D. - - - For reference, here's my pull request for const(Object)ref: <https://github.com/D-Programming-Language/dmd/pull/3>. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
May 17 2011
next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
So how do functions which take such a parameter look like?

void bar(ref Foo a, const(Foo) ref b) { }

or

void bar(ref Foo a, ref const(Foo) b) { }
May 17 2011
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-05-17 23:48:35 -0400, Andrej Mitrovic 
<andrej.mitrovich gmail.com> said:

 So how do functions which take such a parameter look like?
What do you mean by what they'll look like? They'll look like how you wrote them. I'm not sure I understand the question... but I'll still try to answer.
 void bar(ref Foo a, const(Foo) ref b) { }
 
 void bar(ref Foo a, ref const(Foo) b) { }
With my patch, assuming Foo is a class, the above is the same thing as: void bar(ref Foo ref a, const(Foo) ref b) { } void bar(ref Foo ref a, ref const(Foo ref) b) { } The postfix "ref" represents the object's rebindable reference, while the prefix "ref" is a non-rebindable reference to that object reference. I'm aware that using "ref" both for variable reference and object reference can look a little confusing at times. Changing the postfix "ref" for another symbol would help make things clearer. That said, given that most of the time you don't have to write the "ref" part -- as it is implicit -- I'm not sure it is worth spending a new character token for it either. - - - Also, I usually prefer to stick the postfix "ref" to the closing parenthesis, no space in between, like this: const(Foo)ref It does not matter at all when parsing, but I find that this way I'm more inclined to see the ref as part of the type rather than some kind of separate attribute. Of course you have to leave the space when there is no attribute and no parenthesis (as in "Foo ref"), but for those cases I just drop the "ref" because it's implicit anyway. This is just my personal style. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
May 18 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
 On 2011-05-17 23:48:35 -0400, Andrej Mitrovic
 <andrej.mitrovich gmail.com> said:

 So how do functions which take such a parameter look like?
What do you mean by what they'll look like? They'll look like how you wrote them. I'm not sure I understand the question... but I'll still try to answer.
 void bar(ref Foo a, const(Foo) ref b) { }

 void bar(ref Foo a, ref const(Foo) b) { }
With my patch, assuming Foo is a class, the above is the same thing as: void bar(ref Foo ref a, const(Foo) ref b) { } void bar(ref Foo ref a, ref const(Foo ref) b) { } The postfix "ref" represents the object's rebindable reference, while the prefix "ref" is a non-rebindable reference to that object reference. I'm aware that using "ref" both for variable reference and object reference can look a little confusing at times. Changing the postfix "ref" for another symbol would help make things clearer. That said, given that most of the time you don't have to write the "ref" part -- as it is implicit -- I'm not sure it is worth spending a new character token for it either. - - - Also, I usually prefer to stick the postfix "ref" to the closing parenthesis, no space in between, like this: const(Foo)ref It does not matter at all when parsing, but I find that this way I'm more inclined to see the ref as part of the type rather than some kind of separate attribute. Of course you have to leave the space when there is no attribute and no parenthesis (as in "Foo ref"), but for those cases I just drop the "ref" because it's implicit anyway. This is just my personal style. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Given that reference types do not support the semantics asked for at all (with transitive const/immutable), I think this is as consistent as it can get. (also way better than "obj<insert storage specifier here>" all over the place.) Am I correct when I assume that, if Foo is a class then Foo ref is the same type as Foo, but const(Foo ref)ref is not a valid type while const(Foo) ref is a valid type? Are there any strange implications for pattern matching? For example: alias const(Foo)ref T; static if(is(T U : const(U)ref){ //would it match? If yes, what is U? Foo ref? } Timon
May 18 2011
parent Michel Fortin <michel.fortin michelf.com> writes:
On 2011-05-18 10:46:19 -0400, Timon Gehr <timon.gehr gmx.ch> said:

 Given that reference types do not support the semantics asked for at all (with
 transitive const/immutable), I think this is as consistent as it can get. (also
 way better than "obj<insert storage specifier here>" all over the place.)
 Am I correct when I assume that, if Foo is a class then
 
 Foo ref is the same type as Foo,
Yes.
 but const(Foo ref)ref is not a valid type while const(Foo) ref is a valid type?
Yes and no. With my patch, "const(Foo ref)ref" is invalid: const(Foo ref)ref o; // error But that's only disallowed at the syntactic level. Semantically, it works, so if you use some kind of indirection. So with an alias it's still allowed: alias Foo ref F; const(F)ref o; // ok
 Are there any strange implications for pattern matching?
 
 For example:
 
 alias const(Foo)ref T;
 static if(is(T U : const(U)ref){
     //would it match? If yes, what is U? Foo ref?
 }
U should be "Foo", which is indeed synonymous to "Foo ref". I admit it's a little strange, but I don't think there's a better way to do it. Unfortunately, your example above isn't taken care of correctly with my patch. There'll still be a couple of things to fix regarding type deduction, like the one above. But type deduction doesn't work too well in a lot of cases for pointer either, making it hard for me to make it work right for "Object ref". See my test case for this in the pull request, each line with a FIXME comment is (in my opinion) a bug: <https://github.com/D-Programming-Language/dmd/pull/3/files#diff-21> I think pointer type deduction and Object ref type deduction will require some more work. In theory they should work pretty much the same, except for the strangeness you noted above where "Foo" is the same as "Foo ref". -- Michel Fortin michel.fortin michelf.com http://michelf.com/
May 18 2011
prev sibling parent reply Christopher the Magnificent <ultimatemacfanatic gmail.com> writes:
Mr. Fortin, thank you for your thorough response.  I have just a few 
comments.

On 5/17/11 9:07 PM, Michel Fortin wrote:
 On 2011-05-17 20:00:55 -0400, Christopher the Magnificent
 <ultimatemacfanatic gmail.com> said:

 Now I understand that another syntax has been nominated to do this job
 which is the const(Object)ref syntax.
I don't think there has been any official word on that. But many people have shown support for it.
 I dislike that syntax because "const(Object)" means a constant
 variable referencing a constant data structure, and "const(Object)ref"
 LOOKS like it should be a reference to a variable of type
 "const(Object)" -- to me it suggests a variable referencing a constant
 variable referencing a constant data structure. "const(Object)ref"
 suggests TWO levels of pointers, but that is not the meaning being
 ascribed thereunto.
But ask yourself this: why does "Object ref" looks like a double reference to you? I'll guess an answer: because of previous knowledge of the language that says to you that "Object" is always implicitly a reference type.
I think that previous knowledge of the language ought to inform the direction of future additions. My previous knowledge of D says that, as in Java, a variable of type Object (where Object is a class-based type) is a reference type.
 The basic idea behind the const(Object)ref proposal is to change the
 meaning of "Object" to become a shortcut for "Object ref".
I disagree that this is something that should be changed. In other
 word, the "ref" part is always there, and if you omit it, it's added
 implicitly for you.
I am personally opposed to giving "Object" and "Object ref" the exact same meaning. This strikes me as confusing because we have been conditioned to understand that "Object" means reference to data structure for an object, but in the second instance "Object" refers to the data structure itself. Inconsistent and confusing, say I. Try to look at thing from a this new perspective and
 it'll fit better.

 I picked the keywords "objconst" and "objimmutable" to suggest that
 the object data structure (hence the "obj" prefix) is immutable or
 const. This was a compromise between brevity and descriptiveness. I
 suppose they could also go "constobj" and "immutableobj".
Personally, I like better the feel of const(Object)ref than any of these keywords. For one thing, it doesn't require any new keyword.
I would argue that adding new keywords is a better way to go because we're not giving the "ref" keyword two distinct but very subtly different uses.
 For
 another, it's perfectly in line with how you do it for pointers. Also,
 it'll work for 'shared' and 'inout' too (once 'inout' works properly).
Are you saying that objconst and objimmutable would NOT work for shared and inout? Why is that?
 Working like pointers has other advantages too: it allow you to
 transpose your understanding of type deduction and type matching in
 templates and is-expressions freely between pointers and objects
 references. Making the syntax different adds a barrier to applying your
 experience of one to the other, this barrier simply does not exist with
 const(Object)ref because the syntax is similar enough to const(S)*.

 Another reason why the objconst/objimmutable syntax is better than
 "const(Object)ref" is that it requires fewer tokens to parse and to
 type -- this makes it easier to read:

 const(Object) ref a; // 5 tokens in the type
 objconst Object a; // only 2 tokens
Easier to type, granted. Easier to read, I'm not so sure; mimicking the existing syntax for pointer makes things more coherent. Easier to parse, I'm not too sure about that either, but it's quite irrelevant anyway. What's difficult is implementing the corresponding semantics in the compiler. The main reason being that, unlike the common perception people have, it's only the compiler backend that deals with class types the same way it deals with pointers. Type attributes (const, immutable, shared, inout) are enforced in the frontend, and the frontend has no separate type for an object and an object reference, and thus no way to attach attributes to the reference separately from the main object type. As the entirety of the frontend is written with that assumption in mind, it's hard to overcome without rewriting a very big portion of the code.
When I said easier to parse, I meant by human eyes. Sorry, I should have made that clearer.
 Now, I figured a way around that, one that Walter will hopefully accept
 once he find enough time to review my patch. If he thinks another syntax
 (such as yours) is more appropriate, it should a pretty trivial change.
 But my preference remains with const(Object)ref.
I still like my proposal best, BUT I would rather see your syntax be selected over mine than for us to be left with no better option than to use Rebindable to get mutable references to constant object data structures.
 Thanks for your input Christopher, and welcome to D.
You're welcome. I'm glad to be joining the D community. Thanks for taking the time to write a thoughtful reply to my postings.
 - - -

 For reference, here's my pull request for const(Object)ref:
 <https://github.com/D-Programming-Language/dmd/pull/3>.
May 17 2011
next sibling parent sclytrack <sclytrack jackdawkiller.com> writes:
const(deref(Object)) ref obj;
deref(Object) a; //hehe.
May 18 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 18 May 2011 02:20:16 -0400, Christopher the Magnificent  
<ultimatemacfanatic gmail.com> wrote:

 On 5/17/11 9:07 PM, Michel Fortin wrote:
 For
 another, it's perfectly in line with how you do it for pointers. Also,
 it'll work for 'shared' and 'inout' too (once 'inout' works properly).
Are you saying that objconst and objimmutable would NOT work for shared and inout? Why is that?
inout and shared are the same thing as const and immutable, they are type modifiers. So following your scheme, we need objshared and objinout keywords. Not only that, but shared is orthogonal to inout/const/immutable, so if you wanted a rebindable reference to a shared const object, you'd need: objconst objshared Object o; Whereas with Michel's proposal, it's const(shared(Object)) ref o; The argument from Walter will be that const is complicated enough, we don't need more keywords. I know, because he's used that argument before :) One of the only reasons inout made it into the language is because it was an existing (but defunct) keyword. I tend to agree with him on that. Doubling the keywords is not a good idea. -Steve
May 18 2011