digitalmars.D - keywords "objconst" and "objimmutable" vs. const(Object) ref
- Christopher the Magnificent (59/59) May 17 2011 Greetings all. First time poster here.
- %u (2/2) May 17 2011 This is what Rebindable(T) is for:
- Christopher the Magnificent (9/11) May 17 2011 Thanks for the reference, but to me, rebindable feels like a hack. My
- Jesse Phillips (11/26) May 17 2011 Syntax has definitely been a major problem for this feature. Walter's st...
- Christopher the Magnificent (4/30) May 17 2011 Thanks for the background, Jesse Phillips. Do you have any thoughts on
- Jesse Phillips (2/5) May 17 2011 I'm going to go with Michel's reply. The const(Object) ref is more cons...
- Steven Schveighoffer (26/41) May 18 2011 Michel Fortin
- Michel Fortin (48/67) May 17 2011 I don't think there has been any official word on that. But many people
- Andrej Mitrovic (4/4) May 17 2011 So how do functions which take such a parameter look like?
- Michel Fortin (30/34) May 18 2011 What do you mean by what they'll look like? They'll look like how you
- Timon Gehr (13/47) May 18 2011 Given that reference types do not support the semantics asked for at all...
- Michel Fortin (26/41) May 18 2011 Yes and no. With my patch, "const(Foo ref)ref" is invalid:
- Christopher the Magnificent (27/91) May 17 2011 Mr. Fortin, thank you for your thorough response. I have just a few
- sclytrack (2/2) May 18 2011 const(deref(Object)) ref obj;
- Steven Schveighoffer (17/23) May 18 2011 inout and shared are the same thing as const and immutable, they are typ...
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
This is what Rebindable(T) is for: http://www.digitalmars.com/d/2.0/phobos/std_typecons.html
May 17 2011
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.htmlThanks 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
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
On 5/17/11 7:26 PM, Jesse Phillips wrote: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?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
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
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 FortinNow 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
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 tokensEasier 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
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
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
On 2011-05-17 23:48:35 -0400, Andrej Mitrovic <andrej.mitrovich gmail.com> 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, 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? } TimonSo 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
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; // okAre 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
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: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.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".I disagree that this is something that should be changed. In otherword, 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 andit'll fit better.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.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).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)*.When I said easier to parse, I meant by human eyes. Sorry, I should have made that clearer.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 tokensEasier 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.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
const(deref(Object)) ref obj; deref(Object) a; //hehe.
May 18 2011
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: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. -SteveFor 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?
May 18 2011