digitalmars.D - Round III, Brainstorm, Re: Immutable arrays for Walter and rest of us.
- Andrew Fedoniouk (38/38) Jul 03 2005 Let's say we decided that D needs
- Uwe Salomon (53/53) Jul 04 2005 This is too long, i know. Sorry. To sum up the contents:
- Andrew Fedoniouk (50/50) Jul 04 2005 (this is a formalization of the proposal I made before)
- Andrew Fedoniouk (28/28) Jul 04 2005 Proposal also based on assumption that
- Nod (37/44) Jul 04 2005 Heh, I can never resist a brainstorm; my mind thrives in such weather :)
- xs0 (15/46) Jul 05 2005 I proposed this (with in/out/inout) some time ago, with not much
- Nod (22/68) Jul 05 2005 Yeah, I thought it wasn't really a new idea. +1 for you too then, mate :...
- Eugene Pelekhay (59/63) Jul 05 2005 Here is my proposition
- Ben Hinkle (13/19) Jul 05 2005 Do what Walter suggested for 'in' plus 3 things: 1) 'out' return values ...
- Ben Hinkle (19/45) Jul 11 2005 A variation on this is to just use the 'final' keyword and forget about
- Andrew Fedoniouk (11/62) Jul 11 2005 Ben, am I correct thinking that your proposal
- Ben Hinkle (8/17) Jul 11 2005 not exactly - see Walter's post about 'in'. Also in C++ const is a type
- Andrew Fedoniouk (19/40) Jul 11 2005 Hmm, it seems that we are speaking about the same entity but using
- Ben Hinkle (34/50) Jul 11 2005 Not as I read Walter's posts like
- Andrew Fedoniouk (30/88) Jul 11 2005 Practical "ultimate resource immutability" ( a.k.a.
- Ben Hinkle (17/107) Jul 11 2005 As Walter's original post said deep immutability is a contract made by t...
- Andrew Fedoniouk (34/152) Jul 11 2005 I suspect quite opposite:
- Regan Heath (19/25) Jul 11 2005 Doesn't this example:
- Andrew Fedoniouk (7/33) Jul 11 2005 As far as I recall it was some rationale behind this. I'll try to find.
- Ben Hinkle (19/178) Jul 11 2005 I can only assume you haven't read all of Walter's post or that there is...
- Andrew Fedoniouk (70/191) Jul 12 2005 Ben, honestly I don't think that any language barrier is involved here.
- Ben Hinkle (13/102) Jul 12 2005 The in/final proposal would not allow immutable collections of mutable
- Andrew Fedoniouk (8/22) Jul 12 2005 As more I am looking into the problem as more I like
- Ben Hinkle (2/10) Jul 11 2005 sorry for the double post but I should add that C++'s const is not
- Ben Hinkle (4/13) Jul 13 2005 It occured to me a benefit of using a keyword other than 'in' is that it...
- Andrew Fedoniouk (18/31) Jul 13 2005 Yep, in/out is just byval/byref and has nothing common with constness.
- Ben Hinkle (2/6) Jul 13 2005 inout is used often in D to get pass-by-reference semantics without
- Andrew Fedoniouk (7/15) Jul 13 2005 I know. And is it good? It is breaking basic DbC rules I guess.
- Dave (44/66) Jul 13 2005 With Walter's 'explicit in' idea, then having 'inout' "double" as a way ...
- Ben Hinkle (26/121) Jul 13 2005 It can? How about an example like
- Dave (22/163) Jul 13 2005 What I meant by 'the compiler could easily decide that' is that the comp...
- Andrew Fedoniouk (10/105) Jul 13 2005 Such explicit 'in' needs 'mutable' designators for all methods allowing
- Regan Heath (14/23) Jul 13 2005 There are several ways you might want to pass a parameter:
- Regan Heath (15/41) Jul 13 2005 Sorry, by OP I meant "Dave".
- Andrew Fedoniouk (7/55) Jul 13 2005 Are we in gambling business or what?
- Regan Heath (8/61) Jul 13 2005 No, because the point you're missing is that it doesn't matter at all ho...
- Andrew Fedoniouk (8/70) Jul 13 2005 Oh, no, please... this horse is dead already...
- Dave (57/131) Jul 14 2005 Basically, what I (and I think Regan) have in mind is that the compiler ...
- Regan Heath (4/165) Jul 14 2005 Exactly!
- Dave (34/80) Jul 13 2005 IMHO, it wouldn't matter in a good majority of cases where an int (or a ...
- Regan Heath (63/69) Jul 05 2005 'readonly' type modifier (*)
Let's say we decided that D needs read-only references and read-only slices (aka const references and const slices). Let's say that compiler can verify constness with the same quality as detecting that e.g. char[] type has no property 'foobar'. Then I would like to brainstorm about following subjects: 1) Reasonable model of "costness" E.g. implicit constness (C++ style) const typename& - can be applied to any type - new const type created behind the scene. Or explicit constness. E.g. Author can define new array type having no modifying members - define new const type explicitly. Or Delphi style - const parameter is only for string (builtin) type. Or [ your choice is here ] 2) Notation. E.g. how readonly slice will look like in code. Function parameters, etc. 3) How to avoid "clutter". This term appears here not once - means that it is reasonable - so we need to deal with it. ----------------------------------- Please follow rules of brainstrom in this topic: 1) No critique. Like "this is bad". 2) No applauses. Like "this is cool" . 3) Answers on answers shall contain only statements evolving original idea. 4) Please be as much brief as possible. This is an experiment. I many times did brainstorm in team but never in the news conference. In real life BS session is limited by 16-20 minutes. Here let's say it will be one day. Who'll be the first?
Jul 03 2005
This is too long, i know. Sorry. To sum up the contents: * Model: Needs const variables and return types, not only const parameters. * Notation: BasicType ConstModifier RefModifier, for example "char fixed[]". * Clutter: You cannot avoid it with these requirements. 1) Reasonable model of "constness" Most of you seem to want a mechanism that makes it possible for an object (read as: "some logical part of the program") to return some piece of information as a read-only reference. Examples: * Slice of an array that must not be modified. * Reference to a container of objects that only allows traversals and reading. As the receiver of this information has to "prove" to the compiler that he will not modify the read-only reference, there must be a mechanism to declare and check that, too. In more complex programs the receiver often does not work on the information himself, but passes them to some other part of the program ─ which must in turn ensure that he will not modify it. Any implementation of constness that does not provide the above points is not useful as a help for designing & debugging of a program. Thus it will not satisfy those of you who want exactly that, those who want something like C++ const. It may be useful for program optimization (speed), but that is rarely requested apparently. 2) Notation. As we need not only const function parameters, but also const return types and const variables (see above), there should be a syntax like this: BasicType ConstModifier RefModifier BasicType is int, char, ... RefModifier is *, [] Examples: length etc. may be changed. int fixed* is a pointer to an integer that must not be changed. BUT the pointer address may be changed. I do not know how to make this syntax work with object references (as there is no RefModifier there, they are implicitly references). 3) Clutter. In a well-designed program each part should be as independent from the others as possible. This includes that he implements not only the operations that are needed by the rest of the program, but the "full range of reasonable operations". This makes it necessary for every container to provide a non-const API (containers whose contents cannot be changed are useless) and a const API (otherwise it cannot be passed to program parts that are not allowed to modify the contents). This makes it necessary for every part of the program that does not modify some parameter to declare this parameter const. This makes it necessary for every user-defined type to define all its methods const that do not change its contents, that do not even make it possible to change its contents. You cannot avoid clutter with these requirements. Ciao uwe
Jul 04 2005
(this is a formalization of the proposal I made before) 1) Reasonable model of "costness" Preconditions: a) Now it is already possible to implement "readonlyness" for classes and structures "by hands" (see [1] and [2]) and b) completely impossible to implement "readonlyness" for arrays(slices) and pointers. Proposal: to introduce two new types: readonly array/slice and readonly pointer. readonly array/slice type has the same set of attributes as array/slice except of 'mutating' methods: opIndexAssign and length(int newLength) readonly pointer cannot be used for 'dereferncing l-values' : *readonly_pointer = something // invalid opearation. 2) Notation. As current proposal is limited only by arrays and pointers cases then it is possible to avoid use of any keyword like 'const', 'readonly' or 'fixed'. Proposal: to use "readonly brackets" and "readonly star" - special tokens like: or 3) How to avoid "clutter". Usually "const clutter" means [3]: a) "const is a pain to write everywhere," b) "If I use it in one place, I have to use it all the time." As given proposal is not forcing constness propagation then b) problem is significantly less than as with C++ const use cases. In any case one of the purposes of aliasing is to reduce all sorts of clutters, e.g.: --------------------------------------------------------------- [1] Ben Hinkle, MinTL: struct Deque(..., bit ReadOnly = false, ...) http://home.comcast.net/~benhinkle/mintl/ [2] Kris Bell, Mango Tree library Dictionary, MutableDictionary http://mango.dsource.org/Dictionary_8d-source.html [3] Herb Sutter: http://www.gotw.ca/publications/advice98.htm Scott Meyers: http://artima.com/intv/const.html
Jul 04 2005
Proposal also based on assumption that readonly type is a base type having mutating methods removed/disabled. Idea is simple - to allow struct to derive from primitive types (including struct itself). Having this it will be possible to define readonly array as: struct readonly(T:T[]): T[] { private T opIndexAssign(T v, uint i) { return v; } // private - // disabling it for the outer world. private uint length( uint nl ) { return length(); } // private ... readonly opSlice() .... readonly opSlice(uint a, uint b) .... } so string (a.k.a. string-value) will look like as alias readonly!(char[]) string; ---------------------------------------- openrj.d collections might look like class Recordest { private Field[] _fields; alias readonly!(Field[]) Fields; Fields fields() { return cast(Fields) _fields; } } ------------------------------------------- Question remains: what to do with pointers in this case?. -------------------------------------------- Andrew.
Jul 04 2005
Heh, I can never resist a brainstorm; my mind thrives in such weather :) NB: I have not followed this thread from the beginning, so there may be rehashing, misunderstandings, and general unimplementability. Bash away.1) Reasonable model of "costness"The model I suggest is like the Delphi model, only slightly different. This model does not give us general constness, only constness for array contents, and only when passing function boundaries. I suggest a model where "constness" is only a contract like any other. The compiler does a best-effort to detect obvious violations at compile-time, and inserts thorough run-time checks for debug code. In this model, const violations can occur, but should be detected in the debugging phase. This model may seem limited, but I believe it to be sufficient. Remember, we are not trying to emulate strict hardware read-only-ness, we are only trying to avoid accidental alteration by code which does not "own" the data.2) Notation. E.g. how readonly slice will look like in code. Function parameters, etc.When defining a function, we must be able to set constness both on entry and return of the function. One could use the in/inout keywords to mean readonly/readwrite respectively, though this would be quite unintuitive on the return value. Defining the keywords ro/rw to use for this may be better. Example: char[rw] toUpper(char[rw] s) { ... } char[rw] toUpper(char[ro] s) { ... }3) How to avoid "clutter". This term appears here not once - means that it is reasonable - so we need to deal with it.Default to the common case. The ro/rw keywords are not required. If they are left out, we default to whichever is most common. char[] toUpper(char[] s) { ... } // uses defaults The common case can shift depending on context, and on whether we are receiving or returning the array. * When passing an array to a function, read-only is the common case. Thus, one has to explicitly use the "rw" keyword in the prototype if the function alters the array contents. * When returning arrays from functions, and the array was passed to us, the common case is that we can return it as read-write. As such, no "rw" keyword is necessary, in the general case. * When passing an array which is a member variable of the current class, it should be passed read-write between member functions. This list is not exhaustive, of course, but the rest of the defaults are only logical, e.g. always return a private member as read-only.4) Please be as much brief as possible.Well, at least I tried :) -Nod-
Jul 04 2005
When defining a function, we must be able to set constness both on entry and return of the function. One could use the in/inout keywords to mean readonly/readwrite respectively, though this would be quite unintuitive on the return value. Defining the keywords ro/rw to use for this may be better. Example: char[rw] toUpper(char[rw] s) { ... } char[rw] toUpper(char[ro] s) { ... }I proposed this (with in/out/inout) some time ago, with not much response; anyhow, I still think it's a good idea, so +1 from me :) It may make sense to have write-only parameters, too..Agreed.3) How to avoid "clutter". This term appears here not once - means that it is reasonable - so we need to deal with it.Default to the common case. The ro/rw keywords are not required. If they are left out, we default to whichever is most common. char[] toUpper(char[] s) { ... } // uses defaults The common case can shift depending on context, and on whether we are receiving or returning the array. * When passing an array to a function, read-only is the common case. Thus, one has to explicitly use the "rw" keyword in the prototype if the function alters the array contents.* When returning arrays from functions, and the array was passed to us, the common case is that we can return it as read-write. As such, no "rw" keyword is necessary, in the general case.Not agreed. I think read-only arrays would be commonly returned, if such a facility existed. Furthermore, the COW principle suggests that it should be the consumer that .dups, not the producer. Even toUpper from above should not make a copy of the array, if it determines that all characters are upper-case already..* When passing an array which is a member variable of the current class, it should be passed read-write between member functions.Why would you pass a member variable between member functions?This list is not exhaustive, of course, but the rest of the defaults are only logical, e.g. always return a private member as read-only.Well, I think that the rules should be as simple as possible, so I'd say that the default for both function parameters and return values should be read-only (simply because it is the safest thing to do); the default for variables should be rw. xs0
Jul 05 2005
In article <dae7tv$9jv$1 digitaldaemon.com>, xs0 says...Yeah, I thought it wasn't really a new idea. +1 for you too then, mate :) I am not sure write-only parameters is needed though... in/out/inout does this job good enough, me thinks.When defining a function, we must be able to set constness both on entry and return of the function. One could use the in/inout keywords to mean readonly/readwrite respectively, though this would be quite unintuitive on the return value. Defining the keywords ro/rw to use for this may be better. Example: char[rw] toUpper(char[rw] s) { ... } char[rw] toUpper(char[ro] s) { ... }I proposed this (with in/out/inout) some time ago, with not much response; anyhow, I still think it's a good idea, so +1 from me :) It may make sense to have write-only parameters, too..Woot!Agreed.3) How to avoid "clutter". This term appears here not once - means that it is reasonable - so we need to deal with it.Default to the common case. The ro/rw keywords are not required. If they are left out, we default to whichever is most common. char[] toUpper(char[] s) { ... } // uses defaults The common case can shift depending on context, and on whether we are receiving or returning the array. * When passing an array to a function, read-only is the common case. Thus, one has to explicitly use the "rw" keyword in the prototype if the function alters the array contents.Ah yes, but you are thinking about arrays returned from class methods and such (see below). For regular functions, we can usually return it as rw since when a function exits, it immediately stops owning the array.* When returning arrays from functions, and the array was passed to us, the common case is that we can return it as read-write. As such, no "rw" keyword is necessary, in the general case.Not agreed. I think read-only arrays would be commonly returned, if such a facility existed. Furthermore, the COW principle suggests that it should be the consumer that .dups, not the producer. Even toUpper from above should not make a copy of the array, if it determines that all characters are upper-case already..Heh, if one has a big list to choose from perhaps? Ok, that was a bad example, but the same would be true for an array passed into a inner class method, which happens a bit more often. The theory is that when arrays which are hidden by data encapsulation, i.e private, are passed into a scope in which they are normally not visible, they should by default be passed as ro. Conversely, while being passed within scopes which normally *does* have access, the default should be to pass it as rw. And no, I don't know how feasible it is for the compiler to keep track of all this :)* When passing an array which is a member variable of the current class, it should be passed read-write between member functions.Why would you pass a member variable between member functions?I agree that the rules should be as simple as possible, but one set of defaults just won't fit all situations. It's a subjective choice, of course, but I'd rather learn two sets of defaults, one for encapsulated data, and one for without, than have to explicitly specify rw-passing within all my classes.This list is not exhaustive, of course, but the rest of the defaults are only logical, e.g. always return a private member as read-only.Well, I think that the rules should be as simple as possible, so I'd say that the default for both function parameters and return values should be read-only (simply because it is the safest thing to do); the default for variables should be rw.xs0-Nod-
Jul 05 2005
Andrew Fedoniouk wrote:Let's say we decided that D needs read-only references and read-only slices (aka const references and const slices).Here is my proposition Assume that by default reference/slice/pointer is immutable : // mutable string : var char[] s1; : // immutable string : char[] s2; : // slices : s2 = s1; // legal : s1 = s2; // illegal : s2 = s1[1..2]; // legal : s1 = s2[1..2]; // illegal : s1 ~= s2; // legal : s2 ~= s1; // illegal : // function returns mutable string : var char[] func1(){} : // function returns immutable string : char[] func2(){} : // function with argument of immutable string : void func3(char[] s) {} : // function with argument of reference to immutable string : // reference assigned during function call and content can't be : // changed in caller trough returned reference : void func4(out char[] s) {} : // function with argument of initialized immutable string : // that reference can be changed during function call : void func5(inout char[] s) {} : // function with argument of mutable string : // content of string can be changed during function call : void func6(var char[] s) {} : // function with argument of reference to mutable string : // content of string can be changed outside of function : // through returned reference : void func7(out var char[] s) {} : // function with argument of reference to initialized mutable string : // content of string can be changed outside of function or during call : // through returned/passed reference : void func8(inout var char[] s) {} : : // slightly modified code from Regan : // news://news.digitalmars.com:119/opstczhfvz23k2f5 nrage.netwin.co.nz : void foo(char[] string) : var { : void* cmp = null; // defines variable for in/out contracts scope : } : in { : cmp = realloc(cmp,string.sizeof); : memcpy(cmp,&string,string.sizeof); : } : out { : assert(memcmp(cmp,&string,string.sizeof) == 0); : } : body { : //this causes the assert, remove it, no assert. : string.length = 20; : } : // for expression can be extented to support more than one type : // of variable : for(var int i=0; var float f=3.14; i<len; ++i) {}
Jul 05 2005
1) Reasonable model of "costness"Do what Walter suggested for 'in' plus 3 things: 1) 'out' return values 2) 'final' local variables and 3) make violations warn and not error. I think it should be a warning because mixing final/non-final is roughly like passing a signed int to an unsigned int - something fishy is going on but we'll assume the user knows what they are doing until they ask for our advice. In case it isn't obvious an explicit out return value means the output shouldn't be modified by the caller (ie assign it to a final variable or an in parameter). A final local variable is "deep immutable".2) Notation. E.g. how readonly slice will look like in code. Function parameters, etc.void foo(in char[] str); // Walter's idea out char[] foo(); // means output is read-only final char[] str = "blah"; // str is read-only3) How to avoid "clutter". This term appears here not once - means that it is reasonable - so we need to deal with it.Avoids clutter by making it a warning so you don't have to go nuts with final if you don't want to.
Jul 05 2005
"Ben Hinkle" <Ben_member pathlink.com> wrote in message news:dadu5k$1ei$1 digitaldaemon.com...A variation on this is to just use the 'final' keyword and forget about marking output values. So an input parameter, local variable or field marked 'final' means "deep immutable" in Walter's sense for the lifetime of that variable. A final variable of array, pointer or reference type can be assigned new values but the contents of the array, pointer or reference (recursively) cannot change. void foo(final char[] str); // Walter's idea with 'final' instead of 'in' final char[] str = "blah"; // str contents are read-only struct Foo { final char[] str; } If one really misses const outputs a 'final' output value can be spoofed by transforming T foo(); to struct finalT{ final T x;} finalT foo(); although that would get annoying pretty quickly both to write, use and maintain.1) Reasonable model of "costness"Do what Walter suggested for 'in' plus 3 things: 1) 'out' return values 2) 'final' local variables and 3) make violations warn and not error. I think it should be a warning because mixing final/non-final is roughly like passing a signed int to an unsigned int - something fishy is going on but we'll assume the user knows what they are doing until they ask for our advice. In case it isn't obvious an explicit out return value means the output shouldn't be modified by the caller (ie assign it to a final variable or an in parameter). A final local variable is "deep immutable".2) Notation. E.g. how readonly slice will look like in code. Function parameters, etc.void foo(in char[] str); // Walter's idea out char[] foo(); // means output is read-only final char[] str = "blah"; // str is read-only3) How to avoid "clutter". This term appears here not once - means that it is reasonable - so we need to deal with it.Avoids clutter by making it a warning so you don't have to go nuts with final if you don't want to.
Jul 11 2005
"Ben Hinkle" <bhinkle mathworks.com> wrote in message news:datvsm$1e46$1 digitaldaemon.com..."Ben Hinkle" <Ben_member pathlink.com> wrote in message news:dadu5k$1ei$1 digitaldaemon.com...Ben, am I correct thinking that your proposal void foo(final char[] str); // Walter's idea with 'final' instead of 'in' final char[] str = "blah"; // str contents are read-only struct Foo { final char[] str; } uses the same idea as in C++ void foo(const char[] str); const char[] str = "blah"; struct Foo { const char[] str; } but with different keyword?A variation on this is to just use the 'final' keyword and forget about marking output values. So an input parameter, local variable or field marked 'final' means "deep immutable" in Walter's sense for the lifetime of that variable. A final variable of array, pointer or reference type can be assigned new values but the contents of the array, pointer or reference (recursively) cannot change. void foo(final char[] str); // Walter's idea with 'final' instead of 'in' final char[] str = "blah"; // str contents are read-only struct Foo { final char[] str; } If one really misses const outputs a 'final' output value can be spoofed by transforming T foo(); to struct finalT{ final T x;} finalT foo(); although that would get annoying pretty quickly both to write, use and maintain.1) Reasonable model of "costness"Do what Walter suggested for 'in' plus 3 things: 1) 'out' return values 2) 'final' local variables and 3) make violations warn and not error. I think it should be a warning because mixing final/non-final is roughly like passing a signed int to an unsigned int - something fishy is going on but we'll assume the user knows what they are doing until they ask for our advice. In case it isn't obvious an explicit out return value means the output shouldn't be modified by the caller (ie assign it to a final variable or an in parameter). A final local variable is "deep immutable".2) Notation. E.g. how readonly slice will look like in code. Function parameters, etc.void foo(in char[] str); // Walter's idea out char[] foo(); // means output is read-only final char[] str = "blah"; // str is read-only3) How to avoid "clutter". This term appears here not once - means that it is reasonable - so we need to deal with it.Avoids clutter by making it a warning so you don't have to go nuts with final if you don't want to.
Jul 11 2005
Ben, am I correct thinking that your proposal void foo(final char[] str); // Walter's idea with 'final' instead of 'in' final char[] str = "blah"; // str contents are read-only struct Foo { final char[] str; } uses the same idea as in C++ void foo(const char[] str); const char[] str = "blah"; struct Foo { const char[] str; } but with different keyword?not exactly - see Walter's post about 'in'. Also in C++ const is a type modifier and here final would modify a variable like in Java. For information about Java's notion of final see The difference from Java's final is that in Java final means the variable doesn't change but the array or object contents can change and here it would be the reverse - the variable can change but the contents can't. Other than that it's the same as Java's final :-)
Jul 11 2005
"Ben Hinkle" <ben.hinkle gmail.com> wrote in message news:dau6b2$1kuv$1 digitaldaemon.com...Hmm, it seems that we are speaking about the same entity but using different terms. See, in C++ declaration of const variable like const typename v; means declaration of variable of "const typename" - implicitly generated type - const version of typename with all non const members disabled ( non availble ) for use through 'v' alias. Therefore, if I understand you and Walter correctly C++: void foo(const char[] str) is exactly yours: void foo(final char[] str) and Walter's: void foo(in char[] str) Is this correct? Andrew.Ben, am I correct thinking that your proposal void foo(final char[] str); // Walter's idea with 'final' instead of 'in' final char[] str = "blah"; // str contents are read-only struct Foo { final char[] str; } uses the same idea as in C++ void foo(const char[] str); const char[] str = "blah"; struct Foo { const char[] str; } but with different keyword?not exactly - see Walter's post about 'in'. Also in C++ const is a type modifier and here final would modify a variable like in Java. For information about Java's notion of final see The difference from Java's final is that in Java final means the variable doesn't change but the array or object contents can change and here it would be the reverse - the variable can change but the contents can't. Other than that it's the same as Java's final :-)
Jul 11 2005
Hmm, it seems that we are speaking about the same entity but using different terms. See, in C++ declaration of const variable like const typename v; means declaration of variable of "const typename" - implicitly generated type - const version of typename with all non const members disabled ( non availble ) for use through 'v' alias. Therefore, if I understand you and Walter correctly C++: void foo(const char[] str) is exactly yours: void foo(final char[] str) and Walter's: void foo(in char[] str) Is this correct?Not as I read Walter's posts like http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/26096. In particular C++ const says nothing about changing the values through other references while this final/in proposal would assert that the value remains constant through all references. That's been the drum-beat of all these posts saying why D doesn't have const already. I don't understand the confusion here. In addition the final/in proposal is different than C++ const for the following example: struct A { A* ptr; } void foo(final A* ptr2) { ptr2.ptr.ptr = null; // illegal } void main() { A a; a.ptr = &a; foo(&a); } vs in C++ struct A { A* ptr; } void foo(const A* ptr2) { ptr2->ptr->ptr = 0; // legal } void main() { A a; a.ptr = &a; foo(&a); } The example is simplistic but it illustrates the meaning of recursive/deep immutability.
Jul 11 2005
"Ben Hinkle" <bhinkle mathworks.com> wrote in message news:daubr5$1phd$1 digitaldaemon.com...Practical "ultimate resource immutability" ( a.k.a. "Andrei's deep immutability" ) implementation is not feasible on compiler level for langages of D class (e.g. having pointers). Only on VM level it is possible to do it and at some extent only. As "D virtual machine" is a processor itself then it means that without os/hardware support implementation of this dream is not possible. I though that it was clear from the very beginning.... BTW: Do you know any solution for read-only protection of any arbitrary memory location? Highly probable that I missed something in this area recently.Hmm, it seems that we are speaking about the same entity but using different terms. See, in C++ declaration of const variable like const typename v; means declaration of variable of "const typename" - implicitly generated type - const version of typename with all non const members disabled ( non availble ) for use through 'v' alias. Therefore, if I understand you and Walter correctly C++: void foo(const char[] str) is exactly yours: void foo(final char[] str) and Walter's: void foo(in char[] str) Is this correct?Not as I read Walter's posts like http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/26096. In particular C++ const says nothing about changing the values through other references while this final/in proposal would assert that the value remains constant through all references. That's been the drum-beat of all these posts saying why D doesn't have const already. I don't understand the confusion here.In addition the final/in proposal is different than C++ const for the following example: struct A { A* ptr; } void foo(final A* ptr2) { ptr2.ptr.ptr = null; // illegal } void main() { A a; a.ptr = &a; foo(&a); }vs in C++ struct A { A* ptr; } void foo(const A* ptr2) { ptr2->ptr->ptr = 0; // legal }True. I think that C++ behavior in this case can be better as if you would change this to: struct A { A *_ptr; A* ptr() { return _ptr; } }; void foo(const A* ptr2) { ptr2->ptr()->ptr(); // error here } you will get an error: 'ptr' : cannot convert 'this' pointer from 'const struct A' to 'struct A &' or so.void main() { A a; a.ptr = &a; foo(&a); } The example is simplistic but it illustrates the meaning of recursive/deep immutability.Yes it is. As I have shown in example above C++ does such deep immutability. I am using "deep immutability" term as it is described here: http://www-sop.inria.fr/everest/events/cassis05/Transp/poll.pdf
Jul 11 2005
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message news:daui3u$1vos$1 digitaldaemon.com..."Ben Hinkle" <bhinkle mathworks.com> wrote in message news:daubr5$1phd$1 digitaldaemon.com...As Walter's original post said deep immutability is a contract made by the programmer to the compiler (and other programmers) which the compiler can verify in simple cases similar to the cases C++ const would catch. It is independent of any VM or the existence of pointers. Are you trying to say the contract must be verfied in *all* cases? I agree it is impractical to validate all cases. I suspect that's why Walter said the compiler would only catch simple cases like assigning through an immutable pointer and such.Practical "ultimate resource immutability" ( a.k.a. "Andrei's deep immutability" ) implementation is not feasible on compiler level for langages of D class (e.g. having pointers). Only on VM level it is possible to do it and at some extent only. As "D virtual machine" is a processor itself then it means that without os/hardware support implementation of this dream is not possible. I though that it was clear from the very beginning.... BTW: Do you know any solution for read-only protection of any arbitrary memory location? Highly probable that I missed something in this area recently.Hmm, it seems that we are speaking about the same entity but using different terms. See, in C++ declaration of const variable like const typename v; means declaration of variable of "const typename" - implicitly generated type - const version of typename with all non const members disabled ( non availble ) for use through 'v' alias. Therefore, if I understand you and Walter correctly C++: void foo(const char[] str) is exactly yours: void foo(final char[] str) and Walter's: void foo(in char[] str) Is this correct?Not as I read Walter's posts like http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/26096. In particular C++ const says nothing about changing the values through other references while this final/in proposal would assert that the value remains constant through all references. That's been the drum-beat of all these posts saying why D doesn't have const already. I don't understand the confusion here.Sure - if you change the C++ example to not allow any writing then it becomes immutable. But that is different than what I originally posted and what Walter meant by deep immutable parameter.In addition the final/in proposal is different than C++ const for the following example: struct A { A* ptr; } void foo(final A* ptr2) { ptr2.ptr.ptr = null; // illegal } void main() { A a; a.ptr = &a; foo(&a); }vs in C++ struct A { A* ptr; } void foo(const A* ptr2) { ptr2->ptr->ptr = 0; // legal }True. I think that C++ behavior in this case can be better as if you would change this to: struct A { A *_ptr; A* ptr() { return _ptr; } }; void foo(const A* ptr2) { ptr2->ptr()->ptr(); // error here } you will get an error: 'ptr' : cannot convert 'this' pointer from 'const struct A' to 'struct A &' or so.void main() { A a; a.ptr = &a; foo(&a); } The example is simplistic but it illustrates the meaning of recursive/deep immutability.Yes it is. As I have shown in example above C++ does such deep immutability.I am using "deep immutability" term as it is described here: http://www-sop.inria.fr/everest/events/cassis05/Transp/poll.pdfI understand. Do you understand Walter's description of deep immutability from his post? The key phrase in Walter's post is "every sub-object reachable from that parameter". Perhaps we should start using the phrases "deep immutable type" and "deep immutable variable" to distinguish between the notions.
Jul 11 2005
"Ben Hinkle" <bhinkle mathworks.com> wrote in message news:daul84$229o$1 digitaldaemon.com..."Andrew Fedoniouk" <news terrainformatica.com> wrote in message news:daui3u$1vos$1 digitaldaemon.com...I suspect quite opposite: Walter: "On the other hand, look at C++ "const". Nothing about "const" says that some other thread or reference cannot change the value out from under you at any moment. Furthermore, it can be cast away and modified anyway. The semantic value of C++ "const" is essentially zip. This is why I am often flummoxed why it is given such weight in C++." Ben: "Are you trying to say the contract must be verfied in *all* cases?" Of course no. This is Walter who is trying to say this as far as I understand his concerns about 'const' in C++."Ben Hinkle" <bhinkle mathworks.com> wrote in message news:daubr5$1phd$1 digitaldaemon.com...As Walter's original post said deep immutability is a contract made by the programmer to the compiler (and other programmers) which the compiler can verify in simple cases similar to the cases C++ const would catch. It is independent of any VM or the existence of pointers. Are you trying to say the contract must be verfied in *all* cases? I agree it is impractical to validate all cases. I suspect that's why Walter said the compiler would only catch simple cases like assigning through an immutable pointer and such.Practical "ultimate resource immutability" ( a.k.a. "Andrei's deep immutability" ) implementation is not feasible on compiler level for langages of D class (e.g. having pointers). Only on VM level it is possible to do it and at some extent only. As "D virtual machine" is a processor itself then it means that without os/hardware support implementation of this dream is not possible. I though that it was clear from the very beginning.... BTW: Do you know any solution for read-only protection of any arbitrary memory location? Highly probable that I missed something in this area recently.Hmm, it seems that we are speaking about the same entity but using different terms. See, in C++ declaration of const variable like const typename v; means declaration of variable of "const typename" - implicitly generated type - const version of typename with all non const members disabled ( non availble ) for use through 'v' alias. Therefore, if I understand you and Walter correctly C++: void foo(const char[] str) is exactly yours: void foo(final char[] str) and Walter's: void foo(in char[] str) Is this correct?Not as I read Walter's posts like http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/26096. In particular C++ const says nothing about changing the values through other references while this final/in proposal would assert that the value remains constant through all references. That's been the drum-beat of all these posts saying why D doesn't have const already. I don't understand the confusion here.Yes, I think I understand "every sub-object reachable from that parameter". This is exactly referentional deep immutability - "using this particular reference to the object it is impossible to change state of the object and every sub-object reachable from that object" This is what C++ and Javari are doing: "The specific constraint expressed is that the abstract state of the object to which an immutable reference refers cannot be modified using that reference. The abstract state is (part of) the transitively reachable state: that is, the state of the object and all state reachable from it by following references. The type system permits explicitly excluding fields or objects from the abstract state of an object. For a statically type-safe language, the type system guarantees reference immutability." Javari also allows to: "If the language is extended with immutability downcasts, then run-time checks enforce the reference immutability constraints." by making specific changes in VM. C++ is using 'const' and Javari uses 'readonly' for marking parameters, fields and methods. http://pag.csail.mit.edu/~mernst/pubs/ref-immutability-oopsla2004-slides.pdf http://pag.csail.mit.edu/~mernst/pubs/ref-immutability-oopsla2004.pdfSure - if you change the C++ example to not allow any writing then it becomes immutable. But that is different than what I originally posted and what Walter meant by deep immutable parameter.In addition the final/in proposal is different than C++ const for the following example: struct A { A* ptr; } void foo(final A* ptr2) { ptr2.ptr.ptr = null; // illegal } void main() { A a; a.ptr = &a; foo(&a); }vs in C++ struct A { A* ptr; } void foo(const A* ptr2) { ptr2->ptr->ptr = 0; // legal }True. I think that C++ behavior in this case can be better as if you would change this to: struct A { A *_ptr; A* ptr() { return _ptr; } }; void foo(const A* ptr2) { ptr2->ptr()->ptr(); // error here } you will get an error: 'ptr' : cannot convert 'this' pointer from 'const struct A' to 'struct A &' or so.void main() { A a; a.ptr = &a; foo(&a); } The example is simplistic but it illustrates the meaning of recursive/deep immutability.Yes it is. As I have shown in example above C++ does such deep immutability.I am using "deep immutability" term as it is described here: http://www-sop.inria.fr/everest/events/cassis05/Transp/poll.pdfI understand. Do you understand Walter's description of deep immutability from his post? The key phrase in Walter's post is "every sub-object reachable from that parameter". Perhaps we should start using the phrases "deep immutable type" and "deep immutable variable" to distinguish between the notions.
Jul 11 2005
On Mon, 11 Jul 2005 16:09:37 -0700, Andrew Fedoniouk <news terrainformatica.com> wrote:Yes, I think I understand "every sub-object reachable from that parameter". This is exactly referentional deep immutability - "using this particular reference to the object it is impossible to change state of the object and every sub-object reachable from that object" This is what C++ and Javari are doing:Doesn't this example: struct A { A* ptr; } void foo(const A* ptr2) { ptr2->ptr->ptr = 0; // legal } void main() { A a; a.ptr = &a; foo(&a); } show that C++ const does not (by default) protect sub-objects, instead a re-design (as you posted) to also use a getter is required. Walters 'in'/'final' deep immutable idea would not require the getter (if I understand it correctly) and so is surely superior? Regan
Jul 11 2005
"Regan Heath" <regan netwin.co.nz> wrote in message news:opstru1ah323k2f5 nrage.netwin.co.nz...On Mon, 11 Jul 2005 16:09:37 -0700, Andrew Fedoniouk <news terrainformatica.com> wrote:As far as I recall it was some rationale behind this. I'll try to find. In any case implementation of this approach will end up with marking parameters, fields and methods by 'const' or 'readonly'. This is what is being considered by Walter as "cluttering" (I personally don't think so)Yes, I think I understand "every sub-object reachable from that parameter". This is exactly referentional deep immutability - "using this particular reference to the object it is impossible to change state of the object and every sub-object reachable from that object" This is what C++ and Javari are doing:Doesn't this example: struct A { A* ptr; } void foo(const A* ptr2) { ptr2->ptr->ptr = 0; // legal } void main() { A a; a.ptr = &a; foo(&a); } show that C++ const does not (by default) protect sub-objects, instead a re-design (as you posted) to also use a getter is required.Walters 'in'/'final' deep immutable idea would not require the getter (if I understand it correctly) and so is surely superior? Regan
Jul 11 2005
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message news:dauu7h$2a8i$1 digitaldaemon.com..."Ben Hinkle" <bhinkle mathworks.com> wrote in message news:daul84$229o$1 digitaldaemon.com...I can only assume you haven't read all of Walter's post or that there is some language barrier going on here. Let me try to expand on what Walter said. The use of 'in' or 'final' is a promise made by the *programmer* to the compiler to obey the contract. The compiler can validate the contract in a subset of circumstances. The compiler will not and most likely cannot validate the contract in all cases. The whole point is that in/final is a promise by the programmer that nothing will change the value and is independent of what the compiler will or will not be able to validate."Andrew Fedoniouk" <news terrainformatica.com> wrote in message news:daui3u$1vos$1 digitaldaemon.com...I suspect quite opposite: Walter: "On the other hand, look at C++ "const". Nothing about "const" says that some other thread or reference cannot change the value out from under you at any moment. Furthermore, it can be cast away and modified anyway. The semantic value of C++ "const" is essentially zip. This is why I am often flummoxed why it is given such weight in C++." Ben: "Are you trying to say the contract must be verfied in *all* cases?" Of course no. This is Walter who is trying to say this as far as I understand his concerns about 'const' in C++."Ben Hinkle" <bhinkle mathworks.com> wrote in message news:daubr5$1phd$1 digitaldaemon.com...As Walter's original post said deep immutability is a contract made by the programmer to the compiler (and other programmers) which the compiler can verify in simple cases similar to the cases C++ const would catch. It is independent of any VM or the existence of pointers. Are you trying to say the contract must be verfied in *all* cases? I agree it is impractical to validate all cases. I suspect that's why Walter said the compiler would only catch simple cases like assigning through an immutable pointer and such.Practical "ultimate resource immutability" ( a.k.a. "Andrei's deep immutability" ) implementation is not feasible on compiler level for langages of D class (e.g. having pointers). Only on VM level it is possible to do it and at some extent only. As "D virtual machine" is a processor itself then it means that without os/hardware support implementation of this dream is not possible. I though that it was clear from the very beginning.... BTW: Do you know any solution for read-only protection of any arbitrary memory location? Highly probable that I missed something in this area recently.Hmm, it seems that we are speaking about the same entity but using different terms. See, in C++ declaration of const variable like const typename v; means declaration of variable of "const typename" - implicitly generated type - const version of typename with all non const members disabled ( non availble ) for use through 'v' alias. Therefore, if I understand you and Walter correctly C++: void foo(const char[] str) is exactly yours: void foo(final char[] str) and Walter's: void foo(in char[] str) Is this correct?Not as I read Walter's posts like http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/26096. In particular C++ const says nothing about changing the values through other references while this final/in proposal would assert that the value remains constant through all references. That's been the drum-beat of all these posts saying why D doesn't have const already. I don't understand the confusion here.The key difference is that const and Javari encode the "immutability" in the type and the in/final semantics are not encoded in the type (hence my original statement that final/in aren't type modifiers). Please consider again the examples I posted comparing final and const "deep immutability".Yes, I think I understand "every sub-object reachable from that parameter". This is exactly referentional deep immutability - "using this particular reference to the object it is impossible to change state of the object and every sub-object reachable from that object"Sure - if you change the C++ example to not allow any writing then it becomes immutable. But that is different than what I originally posted and what Walter meant by deep immutable parameter.In addition the final/in proposal is different than C++ const for the following example: struct A { A* ptr; } void foo(final A* ptr2) { ptr2.ptr.ptr = null; // illegal } void main() { A a; a.ptr = &a; foo(&a); }vs in C++ struct A { A* ptr; } void foo(const A* ptr2) { ptr2->ptr->ptr = 0; // legal }True. I think that C++ behavior in this case can be better as if you would change this to: struct A { A *_ptr; A* ptr() { return _ptr; } }; void foo(const A* ptr2) { ptr2->ptr()->ptr(); // error here } you will get an error: 'ptr' : cannot convert 'this' pointer from 'const struct A' to 'struct A &' or so.void main() { A a; a.ptr = &a; foo(&a); } The example is simplistic but it illustrates the meaning of recursive/deep immutability.Yes it is. As I have shown in example above C++ does such deep immutability.I am using "deep immutability" term as it is described here: http://www-sop.inria.fr/everest/events/cassis05/Transp/poll.pdfI understand. Do you understand Walter's description of deep immutability from his post? The key phrase in Walter's post is "every sub-object reachable from that parameter". Perhaps we should start using the phrases "deep immutable type" and "deep immutable variable" to distinguish between the notions.This is what C++ and Javari are doing: "The specific constraint expressed is that the abstract state of the object to which an immutable reference refers cannot be modified using that reference. The abstract state is (part of) the transitively reachable state: that is, the state of the object and all state reachable from it by following references. The type system permits explicitly excluding fields or objects from the abstract state of an object. For a statically type-safe language, the type system guarantees reference immutability." Javari also allows to: "If the language is extended with immutability downcasts, then run-time checks enforce the reference immutability constraints." by making specific changes in VM. C++ is using 'const' and Javari uses 'readonly' for marking parameters, fields and methods. http://pag.csail.mit.edu/~mernst/pubs/ref-immutability-oopsla2004-slides.pdf http://pag.csail.mit.edu/~mernst/pubs/ref-immutability-oopsla2004.pdfWalter's post as I understand it avoids using the type system or run-time checks to attempt to enforce immutability. Note the key phrase in the first sentance you quote: "cannot be modified using that reference". Walter is trying to find a solution where that would be replaced with "cannot be modified".
Jul 11 2005
"Ben Hinkle" <ben.hinkle gmail.com> wrote in message news:dav7rm$2hp9$1 digitaldaemon.com..."Andrew Fedoniouk" <news terrainformatica.com> wrote in message news:dauu7h$2a8i$1 digitaldaemon.com...Ben, honestly I don't think that any language barrier is involved here. Probably different thinking context or particular design environment or tasks. Anyway Let me try to reproduce of what I understand so far, (I will cite this): http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/26096 of that parameter, and also every sub-object reachable by that parameter would also be unchangeable. another thread. (This is quite unlike C++ "const".) by the compiler perhaps significantly better code. or another thread, making optimizations based on "const" impossible.) I understand it as: Programmer will try to write code of function with 'in' parameters without side effects - he is expressing following good wishes and threads to modify everything which is reachable from this 'in' parameter". will be false as we are humans) optimizer will try to "generate significantly better code". agreements is significantly better for optimization purposes than 'const' agreements used in C++ (which are also gentlemen agreements). Is this correct? (Sorry, probably it sounds sarcastic, but this is how I am getting it, nothing really personal, I swear you :)"Ben Hinkle" <bhinkle mathworks.com> wrote in message news:daul84$229o$1 digitaldaemon.com...I can only assume you haven't read all of Walter's post or that there is some language barrier going on here. Let me try to expand on what Walter said. The use of 'in' or 'final' is a promise made by the *programmer* to the compiler to obey the contract. The compiler can validate the contract in a subset of circumstances. The compiler will not and most likely cannot validate the contract in all cases. The whole point is that in/final is a promise by the programmer that nothing will change the value and is independent of what the compiler will or will not be able to validate."Andrew Fedoniouk" <news terrainformatica.com> wrote in message news:daui3u$1vos$1 digitaldaemon.com...I suspect quite opposite: Walter: "On the other hand, look at C++ "const". Nothing about "const" says that some other thread or reference cannot change the value out from under you at any moment. Furthermore, it can be cast away and modified anyway. The semantic value of C++ "const" is essentially zip. This is why I am often flummoxed why it is given such weight in C++." Ben: "Are you trying to say the contract must be verfied in *all* cases?" Of course no. This is Walter who is trying to say this as far as I understand his concerns about 'const' in C++."Ben Hinkle" <bhinkle mathworks.com> wrote in message news:daubr5$1phd$1 digitaldaemon.com...As Walter's original post said deep immutability is a contract made by the programmer to the compiler (and other programmers) which the compiler can verify in simple cases similar to the cases C++ const would catch. It is independent of any VM or the existence of pointers. Are you trying to say the contract must be verfied in *all* cases? I agree it is impractical to validate all cases. I suspect that's why Walter said the compiler would only catch simple cases like assigning through an immutable pointer and such.Practical "ultimate resource immutability" ( a.k.a. "Andrei's deep immutability" ) implementation is not feasible on compiler level for langages of D class (e.g. having pointers). Only on VM level it is possible to do it and at some extent only. As "D virtual machine" is a processor itself then it means that without os/hardware support implementation of this dream is not possible. I though that it was clear from the very beginning.... BTW: Do you know any solution for read-only protection of any arbitrary memory location? Highly probable that I missed something in this area recently.Hmm, it seems that we are speaking about the same entity but using different terms. See, in C++ declaration of const variable like const typename v; means declaration of variable of "const typename" - implicitly generated type - const version of typename with all non const members disabled ( non availble ) for use through 'v' alias. Therefore, if I understand you and Walter correctly C++: void foo(const char[] str) is exactly yours: void foo(final char[] str) and Walter's: void foo(in char[] str) Is this correct?Not as I read Walter's posts like http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/26096. In particular C++ const says nothing about changing the values through other references while this final/in proposal would assert that the value remains constant through all references. That's been the drum-beat of all these posts saying why D doesn't have const already. I don't understand the confusion here.Let's imagine that I have immutable collection of mutable objects e.g. values of record in recordset - I can change values but not collection itself. Is it reasonable construction? To use this system practically we need "mutable" keyword or such. In given record-buffer example I will need something like this: void store( in mutable value[] recordValues)This is exactly referentional deep immutability - "using this particular reference to the object it is impossible to change state of the object and every sub-object reachable from that object"The key difference is that const and Javari encode the "immutability" in the type and the in/final semantics are not encoded in the type (hence my original statement that final/in aren't type modifiers). Please consider again the examples I posted comparing final and const "deep immutability".I understand it as: Walter is trying to find verification algorithm which allows to prove that any given object passed through 'in reference' will not be modified by any other reference inside and outside of the function and in other threads. And intention is to do this without modification of type system and without implementation of runtime checks and without any OS/hardware support. And all this above supposed to work reliable with slices and those "free range chickens" named pointers.... Did I get it right? Sounds like "perpetuum mobile" project to be honest. Moreover I believe this problem is close to the Halting Problem of Turing Machine (which was proved to be unsolvable). I think it is fundamentally impossible to prove real immutability of any given memory location at compile time without type constraints. If it would be possible then you will not need GC at all as you will be able to delete exact set of unused resources at any arbitrary source line of your program. This is how I understand it. I hope that I am wrong somewhere here. Andrew Fedoniouk. http://terrainformatica.comThis is what C++ and Javari are doing: "The specific constraint expressed is that the abstract state of the object to which an immutable reference refers cannot be modified using that reference. The abstract state is (part of) the transitively reachable state: that is, the state of the object and all state reachable from it by following references. The type system permits explicitly excluding fields or objects from the abstract state of an object. For a statically type-safe language, the type system guarantees reference immutability." Javari also allows to: "If the language is extended with immutability downcasts, then run-time checks enforce the reference immutability constraints." by making specific changes in VM. C++ is using 'const' and Javari uses 'readonly' for marking parameters, fields and methods. http://pag.csail.mit.edu/~mernst/pubs/ref-immutability-oopsla2004-slides.pdf http://pag.csail.mit.edu/~mernst/pubs/ref-immutability-oopsla2004.pdfWalter's post as I understand it avoids using the type system or run-time checks to attempt to enforce immutability. Note the key phrase in the first sentance you quote: "cannot be modified using that reference". Walter is trying to find a solution where that would be replaced with "cannot be modified".
Jul 12 2005
Let me try to reproduce of what I understand so far, (I will cite this): http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/26096 of that parameter, and also every sub-object reachable by that parameter would also be unchangeable. another thread. (This is quite unlike C++ "const".) guaranteed by the compiler perhaps significantly better code. reference or another thread, making optimizations based on "const" impossible.) I understand it as: Programmer will try to write code of function with 'in' parameters without side effects - he is expressing following good wishes and threads to modify everything which is reachable from this 'in' parameter". will be false as we are humans) optimizer will try to "generate significantly better code". agreements is significantly better for optimization purposes than 'const' agreements used in C++ (which are also gentlemen agreements). Is this correct?yes - that's how I read it, too.(Sorry, probably it sounds sarcastic, but this is how I am getting it, nothing really personal, I swear you :)The in/final proposal would not allow immutable collections of mutable objects - either everything is immutable or nothing is. If it is decided that is important then I agree either another keyword is needed or deep immutability needs to be dropped.Let's imagine that I have immutable collection of mutable objects e.g. values of record in recordset - I can change values but not collection itself. Is it reasonable construction? To use this system practically we need "mutable" keyword or such. In given record-buffer example I will need something like this: void store( in mutable value[] recordValues)This is exactly referentional deep immutability - "using this particular reference to the object it is impossible to change state of the object and every sub-object reachable from that object"The key difference is that const and Javari encode the "immutability" in the type and the in/final semantics are not encoded in the type (hence my original statement that final/in aren't type modifiers). Please consider again the examples I posted comparing final and const "deep immutability".I didn't get the impression that is holding him up. He explicitly says the verification algorithm can be as weak as the compiler author wants - in particular the verfication algorithm can be "always trust the programmer and check nothing". Maybe he is working on a fancy verification algorithm - who knows. I hope he isn't spending much time on it. I think he's mulling over designs to balance the trade-offs between C++ const use-cases, deep immutability and optimization opportunities. The general design is more important to get right than the verification algorithm.I understand it as: Walter is trying to find verification algorithm which allows to prove that any given object passed through 'in reference' will not be modified by any other reference inside and outside of the function and in other threads. And intention is to do this without modification of type system and without implementation of runtime checks and without any OS/hardware support. And all this above supposed to work reliable with slices and those "free range chickens" named pointers.... Did I get it right?This is what C++ and Javari are doing: "The specific constraint expressed is that the abstract state of the object to which an immutable reference refers cannot be modified using that reference. The abstract state is (part of) the transitively reachable state: that is, the state of the object and all state reachable from it by following references. The type system permits explicitly excluding fields or objects from the abstract state of an object. For a statically type-safe language, the type system guarantees reference immutability." Javari also allows to: "If the language is extended with immutability downcasts, then run-time checks enforce the reference immutability constraints." by making specific changes in VM. C++ is using 'const' and Javari uses 'readonly' for marking parameters, fields and methods. http://pag.csail.mit.edu/~mernst/pubs/ref-immutability-oopsla2004-slides.pdf http://pag.csail.mit.edu/~mernst/pubs/ref-immutability-oopsla2004.pdfWalter's post as I understand it avoids using the type system or run-time checks to attempt to enforce immutability. Note the key phrase in the first sentance you quote: "cannot be modified using that reference". Walter is trying to find a solution where that would be replaced with "cannot be modified".
Jul 12 2005
As more I am looking into the problem as more I like simple solution of having read-only arrays and read-only pointers. It is a deterministic and natural solution - can be verified and enforced in 100% cases. Combined with use of existing access specifiers private/public/etc. will be more powerfull than 'const' and yet simple.Let's imagine that I have immutable collection of mutable objects e.g. values of record in recordset - I can change values but not collection itself. Is it reasonable construction? To use this system practically we need "mutable" keyword or such. In given record-buffer example I will need something like this: void store( in mutable value[] recordValues)The in/final proposal would not allow immutable collections of mutable objects - either everything is immutable or nothing is. If it is decided that is important then I agree either another keyword is needed or deep immutability needs to be dropped.
Jul 12 2005
This is what C++ and Javari are doing: "The specific constraint expressed is that the abstract state of the object to which an immutable reference refers cannot be modified using that reference. The abstract state is (part of) the transitively reachable state: that is, the state of the object and all state reachable from it by following references. The type system permits explicitly excluding fields or objects from the abstract state of an object. For a statically type-safe language, the type system guarantees reference immutability."sorry for the double post but I should add that C++'s const is not transitive, as illustrated by the code example I posted before.
Jul 11 2005
A variation on this is to just use the 'final' keyword and forget about marking output values. So an input parameter, local variable or field marked 'final' means "deep immutable" in Walter's sense for the lifetime of that variable. A final variable of array, pointer or reference type can be assigned new values but the contents of the array, pointer or reference (recursively) cannot change. void foo(final char[] str); // Walter's idea with 'final' instead of 'in' final char[] str = "blah"; // str contents are read-only struct Foo { final char[] str; }It occured to me a benefit of using a keyword other than 'in' is that it allows you to write void foo(final inout BigHonkinStruct x) to get both pass-by-reference and immutability.
Jul 13 2005
"Ben Hinkle" <ben.hinkle gmail.com> wrote in message news:db3ejf$i7u$1 digitaldaemon.com...Yep, in/out is just byval/byref and has nothing common with constness. BTW: You've provided example which has little sense :) void foo(final inout BigHonkinStruct x) As 'inout' tells us - information will flow in and out but foo cannot modify x so it is only 'in' in fact. But with immutable arrays and pointers in/out has perfect sense: // struct pointed by x will not be modified inside // foo // const struct // reading some const struct and // returning reference to new const struct Andrew.A variation on this is to just use the 'final' keyword and forget about marking output values. So an input parameter, local variable or field marked 'final' means "deep immutable" in Walter's sense for the lifetime of that variable. A final variable of array, pointer or reference type can be assigned new values but the contents of the array, pointer or reference (recursively) cannot change. void foo(final char[] str); // Walter's idea with 'final' instead of 'in' final char[] str = "blah"; // str contents are read-only struct Foo { final char[] str; }It occured to me a benefit of using a keyword other than 'in' is that it allows you to write void foo(final inout BigHonkinStruct x) to get both pass-by-reference and immutability.
Jul 13 2005
BTW: You've provided example which has little sense :) void foo(final inout BigHonkinStruct x) As 'inout' tells us - information will flow in and out but foo cannot modify x so it is only 'in' in fact.inout is used often in D to get pass-by-reference semantics without intending to modify the contents.
Jul 13 2005
"Ben Hinkle" <bhinkle mathworks.com> wrote in message news:db3hbg$ke8$1 digitaldaemon.com...I know. And is it good? It is breaking basic DbC rules I guess. In any case tells me more than: foo(inout int var)BTW: You've provided example which has little sense :) void foo(final inout BigHonkinStruct x) As 'inout' tells us - information will flow in and out but foo cannot modify x so it is only 'in' in fact.inout is used often in D to get pass-by-reference semantics without intending to modify the contents.
Jul 13 2005
In article <db3g4b$jdj$1 digitaldaemon.com>, Andrew Fedoniouk says..."Ben Hinkle" <ben.hinkle gmail.com> wrote in message news:db3ejf$i7u$1 digitaldaemon.com...With Walter's 'explicit in' idea, then having 'inout' "double" as a way to pass a byval variable (greater in size than a machine word more efficiently) wouldn't be needed - the compiler could easily decide that and just do the optimization. This can be more efficient with something even as small as a long or a double prec. fp var. on 32 bit machines. so instead of 'void foo(final inout BigHonkinStruct x)' or it would just be: 'void foo(in BigHonkinStruct x)' With that in mind, I *still* say both 'implicit in' and 'explicit in' should be changed to act like Walter's proposal because that is what is expected in 99% of the cases anyhow, and the other 1% is when the programmer forgot the 'out' or 'inout' with byref vars. If the compiler detects even the simple cases, then most of the remaining 1% wouldn't compile anyway and the programmer would simply have to change it to 'out' or 'inout' as it should have been in the first place <g>. The other issue with using 'inout' as a substitute for '&' is that you can't pass a temporary: struct S { int x, y, z; } S initAnS(int x, int y, int z) { S s; s.x = x, s.y = y, s.z = z; return s; } int foo(inout S s) { return s.x * s.y * s.z; } void main() { int i = foo(initAnS(10,20,30)); // Error: initAnS(10,20,30) is not an lvalue } The optimizations aren't my biggest deal though -- IMHO, the param. storage specifiers should mean what they say or imply, it's just that the semantics of 'in' (both implicit and explicit) need to change to be like the const or 'readonly' vars. that we've all been talking about and then perhaps (if needed) a contrary keyword like 'mutable' could be added. Will an 'immutable implicit in' be confusing for C/++ people at first? Perhaps, but not after the compiler spits out an error for the first few trivial cases - then it will just be "Ok, if I want to modify a function parameter, I have to specify 'out' or 'inout' or make a copy. Maybe it won't be confusing at all because in C-land they have to use a pointer and in C++ land they have to use '&' so maybe making 'implicit in' act like a Java people wo will be confused at first. I think Walter had it right on his first pass here: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/26096 - DaveYep, in/out is just byval/byref and has nothing common with constness. BTW: You've provided example which has little sense :) void foo(final inout BigHonkinStruct x) As 'inout' tells us - information will flow in and out but foo cannot modify x so it is only 'in' in fact.A variation on this is to just use the 'final' keyword and forget about marking output values. So an input parameter, local variable or field marked 'final' means "deep immutable" in Walter's sense for the lifetime of that variable. A final variable of array, pointer or reference type can be assigned new values but the contents of the array, pointer or reference (recursively) cannot change. void foo(final char[] str); // Walter's idea with 'final' instead of 'in' final char[] str = "blah"; // str contents are read-only struct Foo { final char[] str; }It occured to me a benefit of using a keyword other than 'in' is that it allows you to write void foo(final inout BigHonkinStruct x) to get both pass-by-reference and immutability.
Jul 13 2005
"Dave" <Dave_member pathlink.com> wrote in message news:db3pfk$rje$1 digitaldaemon.com...In article <db3g4b$jdj$1 digitaldaemon.com>, Andrew Fedoniouk says...It can? How about an example like struct BigHonkinStruct { int a; } //ok not so honkin but you get the idea void foo(in BigHonkinStruct x, void delegate() cb) { int old = x.a; cb(); assert( x.a == old ); } void bar() { BigHonkinStruct y; void baz(){y.a = 10;} foo(y,&baz); } Pass-by-value semantics means that the x inside foo is (semantically) a copy of y so the function bar must be able to change y whenever it wants and it has no impact on x. Hence you can't pass y by reference to foo even though it is declared as 'explicit in'. Are you thinking of something else? I might be mis-reading your point."Ben Hinkle" <ben.hinkle gmail.com> wrote in message news:db3ejf$i7u$1 digitaldaemon.com...With Walter's 'explicit in' idea, then having 'inout' "double" as a way to pass a byval variable (greater in size than a machine word more efficiently) wouldn't be needed - the compiler could easily decide that and just do the optimization.Yep, in/out is just byval/byref and has nothing common with constness. BTW: You've provided example which has little sense :) void foo(final inout BigHonkinStruct x) As 'inout' tells us - information will flow in and out but foo cannot modify x so it is only 'in' in fact.A variation on this is to just use the 'final' keyword and forget about marking output values. So an input parameter, local variable or field marked 'final' means "deep immutable" in Walter's sense for the lifetime of that variable. A final variable of array, pointer or reference type can be assigned new values but the contents of the array, pointer or reference (recursively) cannot change. void foo(final char[] str); // Walter's idea with 'final' instead of 'in' final char[] str = "blah"; // str contents are read-only struct Foo { final char[] str; }It occured to me a benefit of using a keyword other than 'in' is that it allows you to write void foo(final inout BigHonkinStruct x) to get both pass-by-reference and immutability.This can be more efficient with something even as small as a long or a double prec. fp var. on 32 bit machines. so instead of 'void foo(final inout BigHonkinStruct x)' or it would just be: 'void foo(in BigHonkinStruct x)' With that in mind, I *still* say both 'implicit in' and 'explicit in' should be changed to act like Walter's proposal because that is what is expected in 99% of the cases anyhow, and the other 1% is when the programmer forgot the 'out' or 'inout' with byref vars. If the compiler detects even the simple cases, then most of the remaining 1% wouldn't compile anyway and the programmer would simply have to change it to 'out' or 'inout' as it should have been in the first place <g>. The other issue with using 'inout' as a substitute for '&' is that you can't pass a temporary: struct S { int x, y, z; } S initAnS(int x, int y, int z) { S s; s.x = x, s.y = y, s.z = z; return s; } int foo(inout S s) { return s.x * s.y * s.z; } void main() { int i = foo(initAnS(10,20,30)); // Error: initAnS(10,20,30) is not an lvalue } The optimizations aren't my biggest deal though -- IMHO, the param. storage specifiers should mean what they say or imply, it's just that the semantics of 'in' (both implicit and explicit) need to change to be like the const or 'readonly' vars. that we've all been talking about and then perhaps (if needed) a contrary keyword like 'mutable' could be added. Will an 'immutable implicit in' be confusing for C/++ people at first? Perhaps, but not after the compiler spits out an error for the first few trivial cases - then it will just be "Ok, if I want to modify a function parameter, I have to specify 'out' or 'inout' or make a copy. Maybe it won't be confusing at all because in C-land they have to use a pointer and in C++ land they have to use '&' so maybe making 'implicit in' act like a byval for even byref parameters will come more naturally and it's the VB, Java people wo will be confused at first. I think Walter had it right on his first pass here: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/26096 - DaveIMHO 'implicit in' forcing immutability would be a big language change from without the compiler throwing fits. I agree if implicit in were changed then a 'mutable' keyword would be needed to avoid having to use inout/out and force lvalues. I also hope it wouldn't encourage people to use global variables in order to avoid passing state around and micro-managing the mutability.
Jul 13 2005
In article <db3so3$u58$1 digitaldaemon.com>, Ben Hinkle says..."Dave" <Dave_member pathlink.com> wrote in message news:db3pfk$rje$1 digitaldaemon.com...What I meant by 'the compiler could easily decide that' is that the compiler could detect whether or not it would be worth it to pass byref or not, not if the compiler could detect 'immutability' cases like that above. I know what pass byval semantics do now <g> Part of what I was getting at is basically that the semantics would have to change -- perhaps get rid of the implicit byval/byref distinction based on what the parameter type is, CT error on the 'easy' cases where 'immutability' is broken for in params and rely on the idea of Walter's 'immutability contract'. It would be one of those areas where D is just different. Continuing the byval/byref though, one of the things that was confusing to people going to Java (where 'everything is an object') is that int 'objects' are passed byval whereas some UDT 'object' is passed byref. So, they ended up modifying an int param in a function and it wouldn't break their code but when they passed a UDT and modified a member of the UDT, it would. This is probably the same with D, expecially for newbies. If you got rid of the implicit byval/byref distinction so people just knew that if you modify 'in' parameter 'x' inside a function it may have side-effects (regardless of the type) then they wouldn't rely on a parameter being byval. This 'mindset' would also help to get rid of hard to find bugs caused by generic programming where the same template functions do something to a type whether or not it resides on the stack or the heap, for example.In article <db3g4b$jdj$1 digitaldaemon.com>, Andrew Fedoniouk says...It can? How about an example like struct BigHonkinStruct { int a; } //ok not so honkin but you get the idea void foo(in BigHonkinStruct x, void delegate() cb) { int old = x.a; cb(); assert( x.a == old ); } void bar() { BigHonkinStruct y; void baz(){y.a = 10;} foo(y,&baz); } Pass-by-value semantics means that the x inside foo is (semantically) a copy of y so the function bar must be able to change y whenever it wants and it has no impact on x. Hence you can't pass y by reference to foo even though it is declared as 'explicit in'. Are you thinking of something else? I might be mis-reading your point."Ben Hinkle" <ben.hinkle gmail.com> wrote in message news:db3ejf$i7u$1 digitaldaemon.com...With Walter's 'explicit in' idea, then having 'inout' "double" as a way to pass a byval variable (greater in size than a machine word more efficiently) wouldn't be needed - the compiler could easily decide that and just do the optimization.Yep, in/out is just byval/byref and has nothing common with constness. BTW: You've provided example which has little sense :) void foo(final inout BigHonkinStruct x) As 'inout' tells us - information will flow in and out but foo cannot modify x so it is only 'in' in fact.A variation on this is to just use the 'final' keyword and forget about marking output values. So an input parameter, local variable or field marked 'final' means "deep immutable" in Walter's sense for the lifetime of that variable. A final variable of array, pointer or reference type can be assigned new values but the contents of the array, pointer or reference (recursively) cannot change. void foo(final char[] str); // Walter's idea with 'final' instead of 'in' final char[] str = "blah"; // str contents are read-only struct Foo { final char[] str; }It occured to me a benefit of using a keyword other than 'in' is that it allows you to write void foo(final inout BigHonkinStruct x) to get both pass-by-reference and immutability.This can be more efficient with something even as small as a long or a double prec. fp var. on 32 bit machines. so instead of 'void foo(final inout BigHonkinStruct x)' or it would just be: 'void foo(in BigHonkinStruct x)' With that in mind, I *still* say both 'implicit in' and 'explicit in' should be changed to act like Walter's proposal because that is what is expected in 99% of the cases anyhow, and the other 1% is when the programmer forgot the 'out' or 'inout' with byref vars. If the compiler detects even the simple cases, then most of the remaining 1% wouldn't compile anyway and the programmer would simply have to change it to 'out' or 'inout' as it should have been in the first place <g>. The other issue with using 'inout' as a substitute for '&' is that you can't pass a temporary: struct S { int x, y, z; } S initAnS(int x, int y, int z) { S s; s.x = x, s.y = y, s.z = z; return s; } int foo(inout S s) { return s.x * s.y * s.z; } void main() { int i = foo(initAnS(10,20,30)); // Error: initAnS(10,20,30) is not an lvalue } The optimizations aren't my biggest deal though -- IMHO, the param. storage specifiers should mean what they say or imply, it's just that the semantics of 'in' (both implicit and explicit) need to change to be like the const or 'readonly' vars. that we've all been talking about and then perhaps (if needed) a contrary keyword like 'mutable' could be added. Will an 'immutable implicit in' be confusing for C/++ people at first? Perhaps, but not after the compiler spits out an error for the first few trivial cases - then it will just be "Ok, if I want to modify a function parameter, I have to specify 'out' or 'inout' or make a copy. Maybe it won't be confusing at all because in C-land they have to use a pointer and in C++ land they have to use '&' so maybe making 'implicit in' act like a byval for even byref parameters will come more naturally and it's the VB, Java people wo will be confused at first. I think Walter had it right on his first pass here: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/26096 - DaveIMHO 'implicit in' forcing immutability would be a big language change from without the compiler throwing fits. I agree if implicit in were changed then a 'mutable' keyword would be needed to avoid having to use inout/out and force lvalues. I also hope it wouldn't encourage people to use global variables in order to avoid passing state around and micro-managing the mutability.
Jul 13 2005
"Dave" <Dave_member pathlink.com> wrote in message news:db3pfk$rje$1 digitaldaemon.com...In article <db3g4b$jdj$1 digitaldaemon.com>, Andrew Fedoniouk says...Such explicit 'in' needs 'mutable' designators for all methods allowing to change state of structure/class. This is the main concern with 'const' in C++ Again 'in' is a direction of information flow. Please don't mix them with constantess. Through 'in' you can pass both mutable reference and immutable reference. 'in' just means that changes of reference value itself will not be visible for a caller - it is far from "this pointer is only for reading"."Ben Hinkle" <ben.hinkle gmail.com> wrote in message news:db3ejf$i7u$1 digitaldaemon.com...With Walter's 'explicit in' idea, then having 'inout' "double" as a way to pass a byval variable (greater in size than a machine word more efficiently) wouldn't be needed - the compiler could easily decide that and just do the optimization. This can be more efficient with something even as small as a long or a double prec. fp var. on 32 bit machines. so instead of 'void foo(final inout BigHonkinStruct x)' or it would just be: 'void foo(in BigHonkinStruct x)' With that in mind, I *still* say both 'implicit in' and 'explicit in' should be changed to act like Walter's proposal because that is what is expected in 99% of the cases anyhow, and the other 1% is when the programmer forgot the 'out' or 'inout' with byref vars. If the compiler detects even the simple cases, then most of the remaining 1% wouldn't compile anyway and the programmer would simply have to change it to 'out' or 'inout' as it should have been in the first place <g>. The other issue with using 'inout' as a substitute for '&' is that you can't pass a temporary: struct S { int x, y, z; } S initAnS(int x, int y, int z) { S s; s.x = x, s.y = y, s.z = z; return s; } int foo(inout S s) { return s.x * s.y * s.z; } void main() { int i = foo(initAnS(10,20,30)); // Error: initAnS(10,20,30) is not an lvalue } The optimizations aren't my biggest deal though -- IMHO, the param. storage specifiers should mean what they say or imply, it's just that the semantics of 'in' (both implicit and explicit) need to change to be like the const or 'readonly' vars. that we've all been talking about and then perhaps (if needed) a contrary keyword like 'mutable' could be added. Will an 'immutable implicit in' be confusing for C/++ people at first? Perhaps, but not after the compiler spits out an error for the first few trivial cases - then it will just be "Ok, if I want to modify a function parameter, I have to specify 'out' or 'inout' or make a copy. Maybe it won't be confusing at all because in C-land they have to use a pointer and in C++ land they have to use '&' so maybe making 'implicit in' act like a byval for even byref parameters will come more naturally and it's the VB, Java people wo will be confused at first. I think Walter had it right on his first pass here: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/26096 - DaveYep, in/out is just byval/byref and has nothing common with constness. BTW: You've provided example which has little sense :) void foo(final inout BigHonkinStruct x) As 'inout' tells us - information will flow in and out but foo cannot modify x so it is only 'in' in fact.A variation on this is to just use the 'final' keyword and forget about marking output values. So an input parameter, local variable or field marked 'final' means "deep immutable" in Walter's sense for the lifetime of that variable. A final variable of array, pointer or reference type can be assigned new values but the contents of the array, pointer or reference (recursively) cannot change. void foo(final char[] str); // Walter's idea with 'final' instead of 'in' final char[] str = "blah"; // str contents are read-only struct Foo { final char[] str; }It occured to me a benefit of using a keyword other than 'in' is that it allows you to write void foo(final inout BigHonkinStruct x) to get both pass-by-reference and immutability.
Jul 13 2005
On Wed, 13 Jul 2005 13:29:24 -0700, Andrew Fedoniouk <news terrainformatica.com> wrote:Such explicit 'in' needs 'mutable' designators for all methods allowing to change state of structure/class. This is the main concern with 'const' in C++ Again 'in' is a direction of information flow. Please don't mix them with constantess. Through 'in' you can pass both mutable reference and immutable reference. 'in' just means that changes of reference value itself will not be visible for a caller - it is far from "this pointer is only for reading".There are several ways you might want to pass a parameter: 1. read only. the mechanism of passing copy/byref isn't important you just want a variable you can only read from. the compiler could essentially decide to pass this in any way it likes. if passed byref it would have to enforce read only. 2. copy. you want a copy that you can modify inside the function for the duration of the function. 3. refrence. you want the actual variable so that you can modify it inside the function. Right now D has 2 and 3 covered but not 1. The OP is suggesting something
Jul 13 2005
On Thu, 14 Jul 2005 09:56:02 +1200, Regan Heath <regan netwin.co.nz> wrote:On Wed, 13 Jul 2005 13:29:24 -0700, Andrew Fedoniouk <news terrainformatica.com> wrote:Sorry, by OP I meant "Dave". I realise in, out, and inout currently specify how to pass a variable, but, in they also allow the programmer to declare how they intend to use the variable. So while technically they do not declare constness or similar they imply it in cases. I can't really see a point in ever passing byval, we can instead pass byX (compilers choice) and explicitly copy those variables we need a copy of. Of course in a case like: void foo(int i) { int j = i; } where the compier will pass byvalue (as it's more efficient) and we immediately copy it, making a 2nd copy (no different to how it is today, but), the compiler could optimise this so that the only copy made was 'j', couldn't it? ReganSuch explicit 'in' needs 'mutable' designators for all methods allowing to change state of structure/class. This is the main concern with 'const' in C++ Again 'in' is a direction of information flow. Please don't mix them with constantess. Through 'in' you can pass both mutable reference and immutable reference. 'in' just means that changes of reference value itself will not be visible for a caller - it is far from "this pointer is only for reading".There are several ways you might want to pass a parameter: 1. read only. the mechanism of passing copy/byref isn't important you just want a variable you can only read from. the compiler could essentially decide to pass this in any way it likes. if passed byref it would have to enforce read only. 2. copy. you want a copy that you can modify inside the function for the duration of the function. 3. refrence. you want the actual variable so that you can modify it inside the function. Right now D has 2 and 3 covered but not 1. The OP is suggesting
Jul 13 2005
"Regan Heath" <regan netwin.co.nz> wrote in message news:opstvgxmlz23k2f5 nrage.netwin.co.nz...On Thu, 14 Jul 2005 09:56:02 +1200, Regan Heath <regan netwin.co.nz> wrote:Are we in gambling business or what? Compilation and optimization based on gentlemen's agreements, intentions and brotherhood of men ... I like the abstract idea but may I ask for something more determinstic in this pub?On Wed, 13 Jul 2005 13:29:24 -0700, Andrew Fedoniouk <news terrainformatica.com> wrote:Sorry, by OP I meant "Dave". I realise in, out, and inout currently specify how to pass a variable, but, in they also allow the programmer to declare how they intend to use the variable. So while technically they do not declare constness or similar they imply it in cases. I can't really see a point in ever passing byval, we can instead pass byX (compilers choice) ...Such explicit 'in' needs 'mutable' designators for all methods allowing to change state of structure/class. This is the main concern with 'const' in C++ Again 'in' is a direction of information flow. Please don't mix them with constantess. Through 'in' you can pass both mutable reference and immutable reference. 'in' just means that changes of reference value itself will not be visible for a caller - it is far from "this pointer is only for reading".There are several ways you might want to pass a parameter: 1. read only. the mechanism of passing copy/byref isn't important you just want a variable you can only read from. the compiler could essentially decide to pass this in any way it likes. if passed byref it would have to enforce read only. 2. copy. you want a copy that you can modify inside the function for the duration of the function. 3. refrence. you want the actual variable so that you can modify it inside the function. Right now D has 2 and 3 covered but not 1. The OP is suggesting... and explicitly copy those variables we need a copy of. Of course in a case like: void foo(int i) { int j = i; } where the compier will pass byvalue (as it's more efficient) and we immediately copy it, making a 2nd copy (no different to how it is today, but), the compiler could optimise this so that the only copy made was 'j', couldn't it? Regan
Jul 13 2005
On Wed, 13 Jul 2005 16:08:08 -0700, Andrew Fedoniouk <news terrainformatica.com> wrote:"Regan Heath" <regan netwin.co.nz> wrote in message news:opstvgxmlz23k2f5 nrage.netwin.co.nz...No, because the point you're missing is that it doesn't matter at all how it passes it if you only read from it, does it? (ignoring efficiency for a sec, as that is how the compiler will choose to pass it)On Thu, 14 Jul 2005 09:56:02 +1200, Regan Heath <regan netwin.co.nz> wrote:Are we in gambling business or what?On Wed, 13 Jul 2005 13:29:24 -0700, Andrew Fedoniouk <news terrainformatica.com> wrote:Sorry, by OP I meant "Dave". I realise in, out, and inout currently specify how to pass a variable, but, in they also allow the programmer to declare how they intend to use the variable. So while technically they do not declare constness or similar they imply it in cases. I can't really see a point in ever passing byval, we can instead pass byX (compilers choice) ...Such explicit 'in' needs 'mutable' designators for all methods allowing to change state of structure/class. This is the main concern with 'const' in C++ Again 'in' is a direction of information flow. Please don't mix them with constantess. Through 'in' you can pass both mutable reference and immutable reference. 'in' just means that changes of reference value itself will not be visible for a caller - it is far from "this pointer is only for reading".There are several ways you might want to pass a parameter: 1. read only. the mechanism of passing copy/byref isn't important you just want a variable you can only read from. the compiler could essentially decide to pass this in any way it likes. if passed byref it would have to enforce read only. 2. copy. you want a copy that you can modify inside the function for the duration of the function. 3. refrence. you want the actual variable so that you can modify it inside the function. Right now D has 2 and 3 covered but not 1. The OP is suggestingCompilation and optimization based on gentlemen's agreements, intentions and brotherhood of men ... I like the abstract idea but may I ask for something more determinstic in this pub?When? Is there any situation where you only want to read from a variable and you must have it passed by value, or by reference? Regan
Jul 13 2005
"Regan Heath" <regan netwin.co.nz> wrote in message news:opstvj1qwe23k2f5 nrage.netwin.co.nz...On Wed, 13 Jul 2005 16:08:08 -0700, Andrew Fedoniouk <news terrainformatica.com> wrote:Oh, no, please... this horse is dead already... "1. ... if passed byref it would have to enforce read only." How the hell compiler will enforce it? This is the whole point. Check can be made in runtime by running GC-like cycle against this variable. This is the only non-intrusive way as far as I know. Do you like it? Andrew."Regan Heath" <regan netwin.co.nz> wrote in message news:opstvgxmlz23k2f5 nrage.netwin.co.nz...No, because the point you're missing is that it doesn't matter at all how it passes it if you only read from it, does it? (ignoring efficiency for a sec, as that is how the compiler will choose to pass it)On Thu, 14 Jul 2005 09:56:02 +1200, Regan Heath <regan netwin.co.nz> wrote:Are we in gambling business or what?On Wed, 13 Jul 2005 13:29:24 -0700, Andrew Fedoniouk <news terrainformatica.com> wrote:Sorry, by OP I meant "Dave". I realise in, out, and inout currently specify how to pass a variable, but, in they also allow the programmer to declare how they intend to use the variable. So while technically they do not declare constness or similar they imply it in cases. I can't really see a point in ever passing byval, we can instead pass byX (compilers choice) ...Such explicit 'in' needs 'mutable' designators for all methods allowing to change state of structure/class. This is the main concern with 'const' in C++ Again 'in' is a direction of information flow. Please don't mix them with constantess. Through 'in' you can pass both mutable reference and immutable reference. 'in' just means that changes of reference value itself will not be visible for a caller - it is far from "this pointer is only for reading".There are several ways you might want to pass a parameter: 1. read only. the mechanism of passing copy/byref isn't important you just want a variable you can only read from. the compiler could essentially decide to pass this in any way it likes. if passed byref it would have to enforce read only. 2. copy. you want a copy that you can modify inside the function for the duration of the function. 3. refrence. you want the actual variable so that you can modify it inside the function. Right now D has 2 and 3 covered but not 1. The OP is suggestingCompilation and optimization based on gentlemen's agreements, intentions and brotherhood of men ... I like the abstract idea but may I ask for something more determinstic in this pub?When? Is there any situation where you only want to read from a variable and you must have it passed by value, or by reference? Regan
Jul 13 2005
In article <db4umv$1spa$1 digitaldaemon.com>, Andrew Fedoniouk says..."Regan Heath" <regan netwin.co.nz> wrote in message news:opstvj1qwe23k2f5 nrage.netwin.co.nz...Basically, what I (and I think Regan) have in mind is that the compiler would enforce 'in' params. the same way a C++ compiler would enforce "const [type]" or "const [type] &" params. for analogous types in C++. That way you would get 'C++ const' functionality for params by default (implicit in params would act like Walter's 'explicit in' proposal too). The difference would be that in D, although it wouldn't be enforced "deeply" by the compiler (because as you've pointed out many times that isn't practical), implicit and explicit 'in' would carry a 'gentlemen's agreement' that these are immutable so that 'in' could have semantic value. I think that a pretty high majority of the "oops" cases would be caught by the "const [type] &" checks analogous to what a good C++ compiler does and then the programmer would have to change the param to out or inout or explicitly make a copy. For the other cases it would be undefined behaviour because the 'contract' is being broken. The reasons this makes sense to me are this: - It would cover most cases and therefore eliminate peppering function declarations with type/storage modifiers. - It wouldn't add anything to D syntax. - It would provide (and enforce) the same C++ const type functionality that it seems a lot of people in this discussion have been referring to. - It would seperate how a parameter is passed (byref or byval) from what type it is (struct, class, array, primitive, pointer) so a D programmer could stop thinking about that and the compiler could do what makes the most sense when passing vars. w/o the programmer having to tack '&' onto every param. - Since 'implicit in' parameters are probably and will stay a good majority, the compiler could take advantage of the contract to produce better code inside the function for expressions involving the 'in' params. - It would reinforce the idea that the 'direction' of a param. should coincide with whether or not it is modified inside a function. For example, when passing an instance of a class 'in', you can now (legally) directly modify primitive members of that class and those modifications live past the lifetime of that function call. However, passing an instance of a struct modifying the member won't in many cases, which just seems contradictory to me: class C { int i = 10; } struct S { int i = 10; } template foo(T) { void foo(in T o) { o.i = 20; } } void main() { C c = new C; printf("%d\n",c.i); foo!(C)(c); printf("%d\n",c.i); S s; printf("%d\n",s.i); foo!(S)(s); printf("%d\n",s.i); } One of Walter's goals is to make the compiler much easier to implement than C++, and I'm not sure if doing const param. checks would be one of the things that would severly impact achieving that goal. It *would* require a new mindset, but I think now's the time to try it out. It would be interesting to add (just) the C++-like const checks to the next build and have everyone run their code through it to see how much code it breaks (as in won't compile) and then regress if it causes too many problems. If it isn't too much effort for Walter, I think it'd be worth a try - this may well 'break' less code than changing AA's (as in the other current discussion) would.On Wed, 13 Jul 2005 16:08:08 -0700, Andrew Fedoniouk <news terrainformatica.com> wrote:Oh, no, please... this horse is dead already... "1. ... if passed byref it would have to enforce read only." How the hell compiler will enforce it? This is the whole point."Regan Heath" <regan netwin.co.nz> wrote in message news:opstvgxmlz23k2f5 nrage.netwin.co.nz...No, because the point you're missing is that it doesn't matter at all how it passes it if you only read from it, does it? (ignoring efficiency for a sec, as that is how the compiler will choose to pass it)On Thu, 14 Jul 2005 09:56:02 +1200, Regan Heath <regan netwin.co.nz> wrote:Are we in gambling business or what?On Wed, 13 Jul 2005 13:29:24 -0700, Andrew Fedoniouk <news terrainformatica.com> wrote:Sorry, by OP I meant "Dave". I realise in, out, and inout currently specify how to pass a variable, but, in they also allow the programmer to declare how they intend to use the variable. So while technically they do not declare constness or similar they imply it in cases. I can't really see a point in ever passing byval, we can instead pass byX (compilers choice) ...Such explicit 'in' needs 'mutable' designators for all methods allowing to change state of structure/class. This is the main concern with 'const' in C++ Again 'in' is a direction of information flow. Please don't mix them with constantess. Through 'in' you can pass both mutable reference and immutable reference. 'in' just means that changes of reference value itself will not be visible for a caller - it is far from "this pointer is only for reading".There are several ways you might want to pass a parameter: 1. read only. the mechanism of passing copy/byref isn't important you just want a variable you can only read from. the compiler could essentially decide to pass this in any way it likes. if passed byref it would have to enforce read only. 2. copy. you want a copy that you can modify inside the function for the duration of the function. 3. refrence. you want the actual variable so that you can modify it inside the function. Right now D has 2 and 3 covered but not 1. The OP is suggestingCheck can be made in runtime by running GC-like cycle against this variable. This is the only non-intrusive way as far as I know. Do you like it? Andrew.Compilation and optimization based on gentlemen's agreements, intentions and brotherhood of men ... I like the abstract idea but may I ask for something more determinstic in this pub?When? Is there any situation where you only want to read from a variable and you must have it passed by value, or by reference? Regan
Jul 14 2005
On Thu, 14 Jul 2005 16:10:05 +0000 (UTC), Dave <Dave_member pathlink.com> wrote:In article <db4umv$1spa$1 digitaldaemon.com>, Andrew Fedoniouk says...Exactly! Regan"Regan Heath" <regan netwin.co.nz> wrote in message news:opstvj1qwe23k2f5 nrage.netwin.co.nz...Basically, what I (and I think Regan) have in mind is that the compiler would enforce 'in' params. the same way a C++ compiler would enforce "const [type]" or "const [type] &" params. for analogous types in C++. That way you would get 'C++ const' functionality for params by default (implicit in params would act like Walter's 'explicit in' proposal too). The difference would be that in D, although it wouldn't be enforced "deeply" by the compiler (because as you've pointed out many times that isn't practical), implicit and explicit 'in' would carry a 'gentlemen's agreement' that these are immutable so that 'in' could have semantic value. I think that a pretty high majority of the "oops" cases would be caught by the "const [type] &" checks analogous to what a good C++ compiler does and then the programmer would have to change the param to out or inout or explicitly make a copy. For the other cases it would be undefined behaviour because the 'contract' is being broken. The reasons this makes sense to me are this: - It would cover most cases and therefore eliminate peppering function declarations with type/storage modifiers. - It wouldn't add anything to D syntax. - It would provide (and enforce) the same C++ const type functionality that it seems a lot of people in this discussion have been referring to. - It would seperate how a parameter is passed (byref or byval) from what type it is (struct, class, array, primitive, pointer) so a D programmer could stop thinking about that and the compiler could do what makes the most sense when passing vars. w/o the programmer having to tack '&' onto every param. - Since 'implicit in' parameters are probably and will stay a good majority, the compiler could take advantage of the contract to produce better code inside the function for expressions involving the 'in' params. - It would reinforce the idea that the 'direction' of a param. should coincide with whether or not it is modified inside a function. For example, when passing an instance of a class 'in', you can now (legally) directly modify primitive members of that class and those modifications live past the lifetime of that function call. However, passing an instance of a struct modifying the member won't in many cases, which just seems contradictory to me: class C { int i = 10; } struct S { int i = 10; } template foo(T) { void foo(in T o) { o.i = 20; } } void main() { C c = new C; printf("%d\n",c.i); foo!(C)(c); printf("%d\n",c.i); S s; printf("%d\n",s.i); foo!(S)(s); printf("%d\n",s.i); } One of Walter's goals is to make the compiler much easier to implement than C++, and I'm not sure if doing const param. checks would be one of the things that would severly impact achieving that goal. It *would* require a new mindset, but I think now's the time to try it out. It would be interesting to add (just) the C++-like const checks to the next build and have everyone run their code through it to see how much code it breaks (as in won't compile) and then regress if it causes too many problems. If it isn't too much effort for Walter, I think it'd be worth a try - this may well 'break' less code than changing AA's (as in the other current discussion) would.On Wed, 13 Jul 2005 16:08:08 -0700, Andrew Fedoniouk <news terrainformatica.com> wrote:Oh, no, please... this horse is dead already... "1. ... if passed byref it would have to enforce read only." How the hell compiler will enforce it? This is the whole point."Regan Heath" <regan netwin.co.nz> wrote in message news:opstvgxmlz23k2f5 nrage.netwin.co.nz...No, because the point you're missing is that it doesn't matter at all how it passes it if you only read from it, does it? (ignoring efficiency for a sec, as that is how the compiler will choose to pass it)On Thu, 14 Jul 2005 09:56:02 +1200, Regan Heath <regan netwin.co.nz> wrote:Are we in gambling business or what?On Wed, 13 Jul 2005 13:29:24 -0700, Andrew Fedoniouk <news terrainformatica.com> wrote:Sorry, by OP I meant "Dave". I realise in, out, and inout currently specify how to pass a variable, but, in they also allow the programmer to declare how they intend to use the variable. So while technically they do not declare constness or similar they imply it in cases. I can't really see a point in ever passing byval, we can instead pass byX (compilers choice) ...Such explicit 'in' needs 'mutable' designators for all methods allowing to change state of structure/class. This is the main concern with 'const' in C++ Again 'in' is a direction of information flow. Please don't mix them with constantess. Through 'in' you can pass both mutable reference and immutable reference. 'in' just means that changes of reference value itself will not be visible for a caller - it is far from "this pointer is only for reading".There are several ways you might want to pass a parameter: 1. read only. the mechanism of passing copy/byref isn't important you just want a variable you can only read from. the compiler could essentially decide to pass this in any way it likes. if passed byref it would have to enforce read only. 2. copy. you want a copy that you can modify inside the function for the duration of the function. 3. refrence. you want the actual variable so that you can modify it inside the function. Right now D has 2 and 3 covered but not 1. The OP is suggesting possible
Jul 14 2005
In article <opstvgxmlz23k2f5 nrage.netwin.co.nz>, Regan Heath says...On Thu, 14 Jul 2005 09:56:02 +1200, Regan Heath <regan netwin.co.nz> wrote:Exactly..On Wed, 13 Jul 2005 13:29:24 -0700, Andrew Fedoniouk <news terrainformatica.com> wrote:Sorry, by OP I meant "Dave". I realise in, out, and inout currently specify how to pass a variable, but, in they also allow the programmer to declare how they intend to use the variable. So while technically they do not declare constness or similar they imply it in cases. I can't really see a point in ever passing byval, we can instead pass byX (compilers choice) and explicitly copy those variables we need a copy of.Such explicit 'in' needs 'mutable' designators for all methods allowing to change state of structure/class. This is the main concern with 'const' in C++ Again 'in' is a direction of information flow. Please don't mix them with constantess. Through 'in' you can pass both mutable reference and immutable reference. 'in' just means that changes of reference value itself will not be visible for a caller - it is far from "this pointer is only for reading".There are several ways you might want to pass a parameter: 1. read only. the mechanism of passing copy/byref isn't important you just want a variable you can only read from. the compiler could essentially decide to pass this in any way it likes. if passed byref it would have to enforce read only. 2. copy. you want a copy that you can modify inside the function for the duration of the function. 3. refrence. you want the actual variable so that you can modify it inside the function. Right now D has 2 and 3 covered but not 1. The OP is suggestingOf course in a case like: void foo(int i) { int j = i; } where the compier will pass byvalue (as it's more efficient) and we immediately copy it, making a 2nd copy (no different to how it is today, but), the compiler could optimise this so that the only copy made was 'j', couldn't it?IMHO, it wouldn't matter in a good majority of cases where an int (or a long on 64 bit machines) is passed 'in' anyway because when a simple var. is passed in like that it is usually only part of the rvalue for expressions like: int x = i * 10; and not modified (at least in my experience) so the programmer wouldn't usually feel compelled to make a modifiable copy anyhow. Regardless, I just ran a quick test with the dmd compiler. The optimization you speak of is apparently already done (dead assignment elimination, I think). Compiled w/ either '-version=nocopy' or not (and -O -inline -release) this actually results in the exact same assembly code: #import std.stdio; #void main() #int foo(int x, int y)Regan
Jul 13 2005
The idea I have been posting for the last few weeks...1) Reasonable model of "costness"'readonly' type modifier (*) 'in' (implicit/explicit) parameters are 'readonly' (*) note, this type modifier does *not* create a distinct type, instead it flags a variable as being readonly. More on the flag below. This is the essential and important difference between this and C++ const.2) Notation. E.g. how readonly slice will look like in code. Function parameters, etc.readonly char[] foo() {} //returns a readonly char[] p = foo(); //p is readonly (*) char[] s = p; //s is readonly (*) void bar(char[] p) {} //p is readonly void bar(in char[] p) {} //p is readonly (*) note, the type modifier is not required on variable declarations, instead they become readonly by assignment from a readonly RHS. "readonly char[]" is not a distinct type, it is simply "char[]" with a readonly *compile time* flag set). It's important to note that this readonly cannot be cast away like C++ const, the only way to get a mutable version of a readonly variable is to use dup, eg. void foo(char[] p) //p is readonly { char[] s = p.dup; s[0] = 'a'; ... } This essentially induces correct COW behaviour.3) How to avoid "clutter". This term appears here not once - means that it is reasonable - so we need to deal with it.The common cases require no notation, eg. parameters - read only by default. return values - writable by default. The remaining 'clutter' isn't clutter IMO but a required declaration of the programmers intent. i.e. void bar(out char[] p) {} //I will write to 'p' void bar(inout char[] p) {} //I will read and write to 'p' readonly char[] p = "test"; //p is readonly readonly char[] foo() {} //return is readonly 4) Suggested implementation A large percentage of readonly violations can be detected at compile time by simply flagging variables during the compile phase, passing that flag on during assignment and giving an error when violations are detected. For certain cases eg. char[] s = condition?foo():""; s[0] = 'a'; //? readonly, or not The only soln I can imagine is a runtime readonly flag. This might be too much cost for very little additional gain. It could however be enabled/disabled much like unittest or other dbc features are. In some cases i.e. functions with 'in' parameters runtime protection/detection can be achieved with the following DBC style code which copies and then compares the readonly variables ensuring no violation has occurred. eg. void foo(char[] p) in { copy = malloc(p.sizeof); memcpy(copy,&p,p.sizeof); } out() { assert(memcmp(copy,&p,p.sizeof) == 0); } body { //causes violation p.length = 20; } It's possible this sort of thing could be applied to other scope entrace/exit points. Regan
Jul 05 2005