digitalmars.D - transporting qualifier from parameter to the return value
- Andrei Alexandrescu (16/16) Dec 15 2009 Time has come to make a decision on implementing Steven Schveighoffer's
- Steven Schveighoffer (27/36) Dec 15 2009 I'll note that this is not my proposal, my original proposal is in the
- Michel Fortin (8/13) Dec 15 2009 Seconded. In fact, we could just remove inout from the keyword list if
- Andrei Alexandrescu (5/16) Dec 15 2009 Regardless of legacy, I personally find "inout" more suggestive - the
- Steven Schveighoffer (10/25) Dec 15 2009 "virtual" const :)
- Denis Koroskin (9/35) Dec 16 2009 I suggested sameconst/shareconst. It is longer but I believe it's more
- Michel Fortin (9/25) Dec 16 2009 autoconst?
- bearophile (5/9) Dec 16 2009 Or:
- Walter Bright (2/6) Dec 15 2009 I agree.
- Michel Fortin (52/73) Dec 15 2009 inout? I guess you mean you decided to rename vconst by inout. I can't
- Steven Schveighoffer (15/53) Dec 15 2009 First, the proposal as I see it is to compile *one* copy of doSomething ...
- Michel Fortin (9/16) Dec 15 2009 I see. Well that could work, as long as we don't mix shared with it.
- Steven Schveighoffer (7/14) Dec 15 2009 That's a very good point. My preference would then be to say that it's ...
- Walter Bright (3/4) Dec 15 2009 There is no shared immutable type, attempts to create one simply produce...
- Walter Bright (15/17) Dec 15 2009 Unmentioned in the proposal is is inout a type constructor or a storage
- dsimcha (8/17) Dec 15 2009 I think it's got to be a storage class, or it's only a partial solution....
- Steven Schveighoffer (25/36) Dec 15 2009 type constructor. it has no meaning as a storage class since it's
- Walter Bright (12/25) Dec 15 2009 I meant does it only apply at the top level, or does it apply down
- Jason House (3/9) Dec 16 2009 It has to apply inside types unless we can prove it isn't needed. Consi...
- Steven Schveighoffer (46/54) Dec 19 2009 I've been giving this some thought. inout is a strange beast, and it ha...
- Walter Bright (3/5) Dec 19 2009 You're right. Considerable care has to be taken getting the implicit
- Kagamin (8/19) Dec 16 2009 It's a type constructor just like const and immutable. As to your exampl...
- Walter Bright (16/17) Dec 15 2009 The more I think about this, the more I think it cannot work unless
- Eldar Insafutdinov (2/25) Dec 16 2009 OMG, D is slowly becoming C++
- Kagamin (3/7) Dec 16 2009 Transportation of shared can be done only by duplication of function int...
- Kagamin (3/25) Dec 16 2009 It's a compile-time error: vconst is orthogonal to immutable, so you can...
- Michel Fortin (12/23) Dec 16 2009 I just realized that 'inout' could have a real use even for functions
- Denis Koroskin (4/21) Dec 16 2009 Doesn't work.
- Michel Fortin (11/22) Dec 16 2009 Well, of course it doesn't...
- Steven Schveighoffer (23/38) Dec 16 2009 This is dangerous.
- Michel Fortin (24/42) Dec 16 2009 If you're trying to define a ruke it's simple: you can cast immutable
- Steven Schveighoffer (29/63) Dec 16 2009 That sounds correct.
- Steven Schveighoffer (11/12) Dec 16 2009 2544 (http://d.puremagic.com/issues/show_bug.cgi?id=2544) is a bug that ...
- Kagamin (4/14) Dec 16 2009 Yes, one more level of indirection is needed:
- Walter Bright (2/8) Dec 16 2009 Is this in bugzilla?
- Steven Schveighoffer (5/11) Dec 16 2009 See my post in another part of this thread, there are 3 related bugs in ...
- Walter Bright (3/18) Dec 16 2009 Those all looked possibly different, so I put it in as:
- Jason House (6/33) Dec 16 2009 I initially liked return as the keyword as well, but it's problematic fo...
- Leandro Lucarella (11/32) Dec 18 2009 Looks like inout won:
- Steven Schveighoffer (12/15) Dec 18 2009 Better than not having the feature :)
- Andrei Alexandrescu (4/26) Dec 19 2009 Thank you for your detailed inout proposal and for making us understand
- Jason House (2/26) Dec 19 2009 The docs should also discuss inout variables declared within the functio...
- Steven Schveighoffer (72/79) Dec 19 2009 Yes, good point. Also important is that inout can ONLY be used on stack...
- Jason House (6/15) Dec 20 2009 I meant functions nested inside of functions.
- Steven Schveighoffer (12/28) Dec 20 2009 OK, I get what you are saying now, sorry for the off-topic reply. That ...
Time has come to make a decision on implementing Steven Schveighoffer's proposal: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP2 It's been in the back of my mind for a while now, I don't find a fault with it, it solves a very unpleasant problem that would seriously mar qualifiers, and although it doesn't solve 100% of the potential cases, it does solve a good fraction of them. I am confident that we can require body duplication for the remaining stragglers with a straight face. My main concern is allowing shared to participate to the inout transportation. I am tempted to allow it, but shared is constrained much more severely than the other two. To avoid problems with the existing uses of inout (which is an old synonym for ref), the language requires that you redundantly use inout in the return type as well. We could eliminate that in D3. Any thoughts would be appreciated. Andrei
Dec 15 2009
On Tue, 15 Dec 2009 22:02:59 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Time has come to make a decision on implementing Steven Schveighoffer's proposal: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP2I'll note that this is not my proposal, my original proposal is in the referenced bug 1961. I did modify the DIP a bit.My main concern is allowing shared to participate to the inout transportation. I am tempted to allow it, but shared is constrained much more severely than the other two.It doesn't work, because shared doesn't implicitly cast to const. During the function body, the parameters tagged with inout are treated as if they were tagged as const. It works for immutable, const and mutable because all those implicitly cast to const. Shared isn't the same, because it requires synchronization even when viewed using const. In addition, if you store a pointer to something that is const during such a function, it is valid after the function exits, a pointer to something shared has to go back to being shared after the function exits, it can't remain as const. I think, however, this may not be much of an issue. I don't think there are as many use cases for data types that are meant to be both shared and unshared than there are data types meant to be *only* shared or unshared.To avoid problems with the existing uses of inout (which is an old synonym for ref), the language requires that you redundantly use inout in the return type as well. We could eliminate that in D3.2 points here: 1. inout is not necessarily used on the *entire* return type. For instance, I'd consider inout(T)[] to be the most useful return type for array processing functions, not inout T[]. It would be difficult to eliminate this requirement and still allow such specificity. However, we already have a way to "eliminate" it -- auto. 2. the choice of inout is not my first choice, I'd prefer a new keyword. The inout compromise was meant to subvert the "we already have too many keywords" argument (it was Janice's idea). If there are no objections, I prefer what the DIP proposed, vconst. All I'm saying is, reusing inout is *not* a very important part of the proposal. -Steve
Dec 15 2009
On 2009-12-15 22:41:19 -0500, "Steven Schveighoffer" <schveiguy yahoo.com> said:2. the choice of inout is not my first choice, I'd prefer a new keyword. The inout compromise was meant to subvert the "we already have too many keywords" argument (it was Janice's idea). If there are no objections, I prefer what the DIP proposed, vconst. All I'm saying is, reusing inout is *not* a very important part of the proposal.Seconded. In fact, we could just remove inout from the keyword list if we care about not augmenting the number of keywords. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 15 2009
Michel Fortin wrote:On 2009-12-15 22:41:19 -0500, "Steven Schveighoffer" <schveiguy yahoo.com> said:Regardless of legacy, I personally find "inout" more suggestive - the qualifier goes from input to output. vconst doesn't quite tell me anything. I don't even know what "v" stands for. Andrei2. the choice of inout is not my first choice, I'd prefer a new keyword. The inout compromise was meant to subvert the "we already have too many keywords" argument (it was Janice's idea). If there are no objections, I prefer what the DIP proposed, vconst. All I'm saying is, reusing inout is *not* a very important part of the proposal.Seconded. In fact, we could just remove inout from the keyword list if we care about not augmenting the number of keywords.
Dec 15 2009
On Tue, 15 Dec 2009 23:04:38 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Michel Fortin wrote:"virtual" const :) My original proposal called the technique "Scoped" const, which I think is pretty accurate, since the data is const only for the scope of the function. perhaps sconst? or aconst for "any" const? In any case inout is fine by me if that's what gits 'er done. The only problem I see with inout is that it has legacy issues. -SteveOn 2009-12-15 22:41:19 -0500, "Steven Schveighoffer" <schveiguy yahoo.com> said:Regardless of legacy, I personally find "inout" more suggestive - the qualifier goes from input to output. vconst doesn't quite tell me anything. I don't even know what "v" stands for.2. the choice of inout is not my first choice, I'd prefer a new keyword. The inout compromise was meant to subvert the "we already have too many keywords" argument (it was Janice's idea). If there are no objections, I prefer what the DIP proposed, vconst. All I'm saying is, reusing inout is *not* a very important part of the proposal.Seconded. In fact, we could just remove inout from the keyword list if we care about not augmenting the number of keywords.
Dec 15 2009
On Wed, 16 Dec 2009 07:20:11 +0300, Steven Schveighoffer <schveiguy yahoo.com> wrote:On Tue, 15 Dec 2009 23:04:38 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I suggested sameconst/shareconst. It is longer but I believe it's more descriptive, as it describes that two (or more) types share the same "constness modifier". sameconst(T)[] find(sameconst(T)[] haystack, T needle) { ... } // my solution to your inout(T)[] problem It could be shortened to same(T) but people didn't like it either. I think it should be bikeshed(T)! :)Michel Fortin wrote:"virtual" const :) My original proposal called the technique "Scoped" const, which I think is pretty accurate, since the data is const only for the scope of the function. perhaps sconst? or aconst for "any" const? In any case inout is fine by me if that's what gits 'er done. The only problem I see with inout is that it has legacy issues. -SteveOn 2009-12-15 22:41:19 -0500, "Steven Schveighoffer" <schveiguy yahoo.com> said:Regardless of legacy, I personally find "inout" more suggestive - the qualifier goes from input to output. vconst doesn't quite tell me anything. I don't even know what "v" stands for.2. the choice of inout is not my first choice, I'd prefer a new keyword. The inout compromise was meant to subvert the "we already have too many keywords" argument (it was Janice's idea). If there are no objections, I prefer what the DIP proposed, vconst. All I'm saying is, reusing inout is *not* a very important part of the proposal.Seconded. In fact, we could just remove inout from the keyword list if we care about not augmenting the number of keywords.
Dec 16 2009
On 2009-12-15 23:04:38 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Michel Fortin wrote:autoconst? It goes in the same vein as "auto ref" Walter just introduced to do mostly the same thing with ref (but limited to function templates). -- Michel Fortin michel.fortin michelf.com http://michelf.com/On 2009-12-15 22:41:19 -0500, "Steven Schveighoffer" <schveiguy yahoo.com> said:Regardless of legacy, I personally find "inout" more suggestive - the qualifier goes from input to output. vconst doesn't quite tell me anything. I don't even know what "v" stands for.2. the choice of inout is not my first choice, I'd prefer a new keyword. The inout compromise was meant to subvert the "we already have too many keywords" argument (it was Janice's idea). If there are no objections, I prefer what the DIP proposed, vconst. All I'm saying is, reusing inout is *not* a very important part of the proposal.Seconded. In fact, we could just remove inout from the keyword list if we care about not augmenting the number of keywords.
Dec 16 2009
Michel Fortin:autoconst? It goes in the same vein as "auto ref" Walter just introduced to do mostly the same thing with ref (but limited to function templates).Or: "auto const" Bye, bearophile
Dec 16 2009
Steven Schveighoffer wrote:I think, however, this may not be much of an issue. I don't think there are as many use cases for data types that are meant to be both shared and unshared than there are data types meant to be *only* shared or unshared.I agree.
Dec 15 2009
On 2009-12-15 22:02:59 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Time has come to make a decision on implementing Steven Schveighoffer's proposal: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP2 It's been in the back of my mind for a while now, I don't find a fault with it, it solves a very unpleasant problem that would seriously mar qualifiers, and although it doesn't solve 100% of the potential cases, it does solve a good fraction of them. I am confident that we can require body duplication for the remaining stragglers with a straight face. My main concern is allowing shared to participate to the inout transportation. I am tempted to allow it, but shared is constrained much more severely than the other two. To avoid problems with the existing uses of inout (which is an old synonym for ref), the language requires that you redundantly use inout in the return type as well. We could eliminate that in D3. Any thoughts would be appreciated.inout? I guess you mean you decided to rename vconst by inout. I can't seem to find a better name, so I guess it's good enough. But I see a flaw in accepting shared. And vconst might be a better name after all. Here's the explanation. So what code inout would generate now? Generate one copy of the function for each possible combination? It can't really do otherwise because the const and non-const versions of other functions it calls might be separate functions too, with separate addresses: class Test { void doThat() immutable {} void doThat() const {} void doThat() {} void doThat() shared immutable {} void doThat() shared const {} void doThat() shared {} void doSomething() inout // or vconst { doThat(); // which doThat does it call? } } Let's accept that doSomething is generated in six copies to allow doSomething to call each version of doThat, and let's look at the next case: class Test { void doThat() immutable {} void doThat() shared immutable {} void doSomething() inout // or vconst { doThat(); // which doThat does it call? } } Now you also have the problem that only the shared immutable and non-shared immutable version of doSomething can compile. Should it generate only two functions? What if I remove the body and only the signature remains, how do I know I can't call doSomething on a mutable object? The problem here is conflating constness with sharedness (!). With vconst, you know it can accept any kind of constness, so it's automatically an error if you can't compile the immutable, the mutable and the const version of the function. Mix shared into this and everything is mixed up. So to catch errors correctly you need vconst which would instanciate three versions of the function: mutable, const, immutable, and be an error if one of the three can't compile; and vshared which would instanciate two: thread-local and shared, and be an error if one of the two can't compile. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 15 2009
On Tue, 15 Dec 2009 22:43:55 -0500, Michel Fortin <michel.fortin michelf.com> wrote:On 2009-12-15 22:02:59 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:First, the proposal as I see it is to compile *one* copy of doSomething (see points 5 and 6 in the DIP description). Second, inout (or vconst) implicitly casts to const, so it can call any functions that require const *or* that require inout. Third, and this is kind of a nitpick, inout functions should *require* inout in the return type, otherwise, there's no point, the qualifier could just be const :) So your example is technically invalid. So to answer your question, doSomething can only call: void doThat() const {} and I don't think shared can be involved because there is no common type you can implicitly cast const, immutable, mutable and shared to. One further nitpick, shared immutable is useless :) -SteveTime has come to make a decision on implementing Steven Schveighoffer's proposal: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP2 It's been in the back of my mind for a while now, I don't find a fault with it, it solves a very unpleasant problem that would seriously mar qualifiers, and although it doesn't solve 100% of the potential cases, it does solve a good fraction of them. I am confident that we can require body duplication for the remaining stragglers with a straight face. My main concern is allowing shared to participate to the inout transportation. I am tempted to allow it, but shared is constrained much more severely than the other two. To avoid problems with the existing uses of inout (which is an old synonym for ref), the language requires that you redundantly use inout in the return type as well. We could eliminate that in D3. Any thoughts would be appreciated.inout? I guess you mean you decided to rename vconst by inout. I can't seem to find a better name, so I guess it's good enough. But I see a flaw in accepting shared. And vconst might be a better name after all. Here's the explanation. So what code inout would generate now? Generate one copy of the function for each possible combination? It can't really do otherwise because the const and non-const versions of other functions it calls might be separate functions too, with separate addresses: class Test { void doThat() immutable {} void doThat() const {} void doThat() {} void doThat() shared immutable {} void doThat() shared const {} void doThat() shared {} void doSomething() inout // or vconst { doThat(); // which doThat does it call? } }
Dec 15 2009
On 2009-12-15 23:02:36 -0500, "Steven Schveighoffer" <schveiguy yahoo.com> said:First, the proposal as I see it is to compile *one* copy of doSomething (see points 5 and 6 in the DIP description). Second, inout (or vconst) implicitly casts to const, so it can call any functions that require const *or* that require inout.I see. Well that could work, as long as we don't mix shared with it.Third, and this is kind of a nitpick, inout functions should *require* inout in the return type, otherwise, there's no point, the qualifier could just be const :) So your example is technically invalid.Should it? I think it'd be better to allow it anyway for generic programming... or at least allow inout(void) as the return type. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 15 2009
On Tue, 15 Dec 2009 23:21:49 -0500, Michel Fortin <michel.fortin michelf.com> wrote:On 2009-12-15 23:02:36 -0500, "Steven Schveighoffer" <schveiguy yahoo.com> said:That's a very good point. My preference would then be to say that it's fine to allow not having inout in the return type for the sake of generic programming. Seems similar to allowing returning the result of a void function inside a void function. -SteveThird, and this is kind of a nitpick, inout functions should *require* inout in the return type, otherwise, there's no point, the qualifier could just be const :) So your example is technically invalid.Should it? I think it'd be better to allow it anyway for generic programming... or at least allow inout(void) as the return type.
Dec 15 2009
Steven Schveighoffer wrote:One further nitpick, shared immutable is useless :)There is no shared immutable type, attempts to create one simply produce "immutable".
Dec 15 2009
Andrei Alexandrescu wrote:Time has come to make a decision on implementing Steven Schveighoffer's proposal:Unmentioned in the proposal is is inout a type constructor or a storage class? For example, U[inout(T)]* foo(inout(X)*** p) { ... } This is much more complex to implement than only allowing inout at the top level, i.e. as a storage class. I also prefer the idea of inout on the return type being assumed, rather than explicit: T foo(inout U p) { ... } Yes, there's the legacy compatibility issue there. A long time ago, I suggested using the keyword 'return' for that, instead of inout: T foo(return U p) { ... } which looks fine until you use it for member functions: T foo() return { ... } ugh.
Dec 15 2009
== Quote from Walter Bright (newshound1 digitalmars.com)'s articleAndrei Alexandrescu wrote:I think it's got to be a storage class, or it's only a partial solution. If your above example doesn't work, people will still be forced to resort to all kinds of kludges like using templates and plain old code duplication.Time has come to make a decision on implementing Steven Schveighoffer's proposal:Unmentioned in the proposal is is inout a type constructor or a storage class? For example, U[inout(T)]* foo(inout(X)*** p) { ... }I also prefer the idea of inout on the return type being assumed, rather than explicit: T foo(inout U p) { ... }Not sure how much sense that would make if we go the full storage class route, for example in your above example. It seems like this would be hard to infer. If we go the top level only route, then it seems like a worthwhile thing to save some syntactic noise.
Dec 15 2009
On Tue, 15 Dec 2009 23:43:58 -0500, Walter Bright <newshound1 digitalmars.com> wrote:Andrei Alexandrescu wrote:type constructor. it has no meaning as a storage class since it's entirely transient (it only has any meaning inside functions). You should never be able to declare any part of a global or member variable as inout, because its meaning can change once a function exits. It's almost a beast of it's own, it's mostly like const, but has some quirky extra rules. BTW, I'm unsure if U[inout(T)] should work. Can one implicitly cast U[T] to U[const(T)] ? If not, then it doesn't make sense that U[inout(T)] should even compile. I guess the rule should be if you have a type that contains an inout notation, the complier should verify that if you define 2 types, one that removes all inout decorations, called M, and one that replaces all inout decorations with const, called N, you should be able to cast from M to N implicitly. If not, then the inout type is invalid. For example: int[inout(char)[]]: int[char[]] => M int[const(char)[]] => NTime has come to make a decision on implementing Steven Schveighoffer's proposal:Unmentioned in the proposal is is inout a type constructor or a storage class? For example, U[inout(T)]* foo(inout(X)*** p) { ... }This is much more complex to implement than only allowing inout at the top level, i.e. as a storage class.A storage class does not give you the transitivity that you need to enforce const rules. The inout tag must be carried forth to aliases of the same data.I also prefer the idea of inout on the return type being assumed, rather than explicit: T foo(inout U p) { ... }What about this? T[] foo(inout(U)[] p) {...} Should the return type implicitly be inout(T)[] or inout T[] ? -Steve
Dec 15 2009
Steven Schveighoffer wrote:type constructor. it has no meaning as a storage class since it's entirely transient (it only has any meaning inside functions).I meant does it only apply at the top level, or does it apply down inside types?BTW, I'm unsure if U[inout(T)] should work.I just meant it as a compound type. It could as easily be: bar!(inout(T)) foo(inout X) { ... }I know, but I know how to make it work. There would be problems, though, ensuring that this works: T[] foo(inout T[]) { return "hello"; }This is much more complex to implement than only allowing inout at the top level, i.e. as a storage class.A storage class does not give you the transitivity that you need to enforce const rules. The inout tag must be carried forth to aliases of the same data.What about this? T[] foo(inout(U)[] p) {...} Should the return type implicitly be inout(T)[] or inout T[] ?It would have to be inout(T[])
Dec 15 2009
Walter Bright Wrote:Steven Schveighoffer wrote:It has to apply inside types unless we can prove it isn't needed. Consider a function that accepts inout(T) and returns inout(U). The extraction of U from const(T) is const(U) just like extraction of U from immutable(T) is immutable(U) because of transitivity rules. I don't think a proof exists. Consider class T { U u; } and other more deeply nested variations.type constructor. it has no meaning as a storage class since it's entirely transient (it only has any meaning inside functions).I meant does it only apply at the top level, or does it apply down inside types?
Dec 16 2009
On Wed, 16 Dec 2009 00:57:59 -0500, Walter Bright <newshound1 digitalmars.com> wrote:Steven Schveighoffer wrote:I've been giving this some thought. inout is a strange beast, and it has some interesting rules. For example, let's take a struct with an already const member: struct S { const(char)[] str; } Now, we have a function that uses inout on S: inout(char)[] getStr(inout S s) { return s.str; } This should NOT compile, because if you pass in a mutable or immutable S, then the compiler casts the result back to mutable or immutable! So inout is transitive only for mutable members of data types. It's sort of similar to applying const to a struct with an immutable member, the const doesn't apply to the immutable member, only the mutable ones.type constructor. it has no meaning as a storage class since it's entirely transient (it only has any meaning inside functions).I meant does it only apply at the top level, or does it apply down inside types?It might be workable. The only monkey wrench thrown in is that bar can do conditional compilation based on the constancy of T: template bar(T) { static if(is(T == const)) alias T[] bar; else struct bar { T t1, t2; } } This is no good, because you don't know how to build bar when your unsure if T is const or not (which is the whole point of inout). If the compiler can determine if bar!(T), bar!(const(T)), bar!(immutable(T)) and bar!(inout(T)) generate identical code (except for the constancy of T), then maybe it can forcibly cast the result once the return happens. This might be the only time where inout can be applied to member variables because it's a temporary situation inside an inout function. It's a complex situation, one that probably requires a lot of thinking. My recommendation at this time is to only allow bar!(inout(T)) if it is an alias to something that normally would be returnable/passable to an inout function e.g.: template bar(T) { alias T[] bar; } as for AA's, it might be a case where we should allow it, since we know AA's have the same implementation regardless of type info. -SteveBTW, I'm unsure if U[inout(T)] should work.I just meant it as a compound type. It could as easily be: bar!(inout(T)) foo(inout X) { ... }
Dec 19 2009
Steven Schveighoffer wrote:I've been giving this some thought. inout is a strange beast, and it has some interesting rules.You're right. Considerable care has to be taken getting the implicit conversion rules right. Some of the cases are fairly subtle.
Dec 19 2009
Walter Bright Wrote:Unmentioned in the proposal is is inout a type constructor or a storage class? For example, U[inout(T)]* foo(inout(X)*** p) { ... } This is much more complex to implement than only allowing inout at the top level, i.e. as a storage class.It's a type constructor just like const and immutable. As to your example, imagine inout expands as follows U[T]* foo(X*** p) { ... } U[const(T)]* foo(const(X)*** p) { ... } U[immutable(T)]* foo(immutable(X)*** p) { ... } If this works, then it's ok. Giving it a quick thought, it should work.I also prefer the idea of inout on the return type being assumed, rather than explicit: T foo(inout U p) { ... }Given inout is a type constructor, it's critical for type safety to properly decorate return type: T is mutable and can't play role of inout-qualified type.
Dec 16 2009
Andrei Alexandrescu wrote:Any thoughts would be appreciated.The more I think about this, the more I think it cannot work unless inout is elevated to be a full type constructor, just like const, immutable, and shared are. For example: inout(char[]) foo(inout char[] p) { char[] s = p; return s; // ulp, doesn't work const char[] s = p; return s; // ulp, doesn't work immutable char[] s = p; return s; // ulp, doesn't work auto s = p; return s; // ulp, doesn't work }
Dec 15 2009
Walter Bright Wrote:Andrei Alexandrescu wrote:OMG, D is slowly becoming C++Any thoughts would be appreciated.The more I think about this, the more I think it cannot work unless inout is elevated to be a full type constructor, just like const, immutable, and shared are. For example: inout(char[]) foo(inout char[] p) { char[] s = p; return s; // ulp, doesn't work const char[] s = p; return s; // ulp, doesn't work immutable char[] s = p; return s; // ulp, doesn't work auto s = p; return s; // ulp, doesn't work }
Dec 16 2009
Andrei Alexandrescu Wrote:although it doesn't solve 100% of the potential caseslike what?My main concern is allowing shared to participate to the inout transportation. I am tempted to allow it, but shared is constrained much more severely than the other two.Transportation of shared can be done only by duplication of function into shared and unshared variants, after which inout can be checked only for const-correctness, sharedness being processed by existing type checking code. If you want this typesaver...
Dec 16 2009
Michel Fortin Wrote:class Test { void doThat() immutable {} void doThat() const {} void doThat() {} void doThat() shared immutable {} void doThat() shared const {} void doThat() shared {} void doSomething() inout // or vconst { doThat(); // which doThat does it call? } }Const function will be called. I replied about sharing in another post.class Test { void doThat() immutable {} void doThat() shared immutable {} void doSomething() inout // or vconst { doThat(); // which doThat does it call? } }It's a compile-time error: vconst is orthogonal to immutable, so you can't pass vconst(this) as immutable(this). Immutable methods are callable only on immutable data. Period.
Dec 16 2009
On 2009-12-15 22:02:59 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Time has come to make a decision on implementing Steven Schveighoffer's proposal: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP2 It's been in the back of my mind for a while now, I don't find a fault with it, it solves a very unpleasant problem that would seriously mar qualifiers, and although it doesn't solve 100% of the potential cases, it does solve a good fraction of them. I am confident that we can require body duplication for the remaining stragglers with a straight face.I just realized that 'inout' could have a real use even for functions with no return value. Consider this: void doSomething(inout(Object)[] a, inout(Object)[] b) { a[0] = b[0]; // works only when objects in both arrays have the same constness. } -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 16 2009
On Wed, 16 Dec 2009 16:48:31 +0300, Michel Fortin <michel.fortin michelf.com> wrote:On 2009-12-15 22:02:59 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Doesn't work. doSomething("hello", "world");Time has come to make a decision on implementing Steven Schveighoffer's proposal: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP2 It's been in the back of my mind for a while now, I don't find a fault with it, it solves a very unpleasant problem that would seriously mar qualifiers, and although it doesn't solve 100% of the potential cases, it does solve a good fraction of them. I am confident that we can require body duplication for the remaining stragglers with a straight face.I just realized that 'inout' could have a real use even for functions with no return value. Consider this: void doSomething(inout(Object)[] a, inout(Object)[] b) { a[0] = b[0]; // works only when objects in both arrays have the same constness. }
Dec 16 2009
On 2009-12-16 08:54:03 -0500, "Denis Koroskin" <2korden gmail.com> said:Well, of course it doesn't... Here's what I meant: void doSomething(inout(MyStruct)*[] a, inout(MyStruct)*[] b) { a[0] = b[0]; // works only when structs in both arrays have the same constness. } -- Michel Fortin michel.fortin michelf.com http://michelf.com/I just realized that 'inout' could have a real use even for functions with no return value. Consider this: void doSomething(inout(Object)[] a, inout(Object)[] b) { a[0] = b[0]; // works only when objects in both arrays have the same constness. }Doesn't work. doSomething("hello", "world");
Dec 16 2009
On Wed, 16 Dec 2009 09:21:16 -0500, Michel Fortin <michel.fortin michelf.com> wrote:On 2009-12-16 08:54:03 -0500, "Denis Koroskin" <2korden gmail.com> said:This is dangerous. We should figure out a reason why this shouldn't compile. It's hard for me to wrap my head around it. Either the implicit cast when calling the function shouldn't work, or the assignment shouldn't work. My intuition is that the implicit cast should fail. Consider the following function with today's notation: void doSomething(const(MyStruct)*[] a, const(MyStruct*)[] b) { a[0] = b[0]; } Now: immutable(MyStruct)*[] im; MyStruct*[] mut; MyStruct *s = new MyStruct; mut ~= s; im.length = 1; doSomething(im, mut); Oops, without a cast, we have changed s into an immutable struct. Hidden inside a function no less! Does this code compile today? If so, we need to fix this. With this fixed, the inout version naturally becomes invalid. -SteveWell, of course it doesn't... Here's what I meant: void doSomething(inout(MyStruct)*[] a, inout(MyStruct)*[] b) { a[0] = b[0]; // works only when structs in both arrays have the same constness. }I just realized that 'inout' could have a real use even for functions with no return value. Consider this: void doSomething(inout(Object)[] a, inout(Object)[] b) { a[0] = b[0]; // works only when objects in both arrays have the same constness. }Doesn't work. doSomething("hello", "world");
Dec 16 2009
On 2009-12-16 14:02:35 -0500, "Steven Schveighoffer" <schveiguy yahoo.com> said:On Wed, 16 Dec 2009 09:21:16 -0500, Michel Fortin <michel.fortin michelf.com> wrote:If you're trying to define a ruke it's simple: you can cast immutable to const only on the first level of indirection, or when there is no indirection. So basically those conversions should be allowed: immutable(MyStruct)*[] -> const(MyStruct*)[] immutable(MyStruct*)[] -> const(MyStruct*)[] immutable(MyStruct*[]) -> const(MyStruct*[]) So the above function can only be called wiHere's what I meant: void doSomething(inout(MyStruct)*[] a, inout(MyStruct)*[] b) { a[0] = b[0]; // works only when structs in both arrays have the same constness. }This is dangerous. We should figure out a reason why this shouldn't compile. It's hard for me to wrap my head around it. Either the implicit cast when calling the function shouldn't work, or the assignment shouldn't work. My intuition is that the implicit cast should fail.Does this code compile today? If so, we need to fix this. With this fixed, the inout version naturally becomes invalid.Just did a couple of small tests. Apparently everything is all right: test.d(18): Error: cannot implicitly convert expression (a) of type immutable(int)*[] to const(int)*[] Also: test.d(18): Error: cannot implicitly convert expression (b) of type int*[] to const(int)*[] Which is right otherwise you could assign immutable values to the array others see as mutable. Also, converting from immutable(int)*[] to const(int*)[] implicitly works fine and does prevent dangerous assignments. So I don't think there is anything to fix on this front. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 16 2009
On Wed, 16 Dec 2009 14:43:47 -0500, Michel Fortin <michel.fortin michelf.com> wrote:On 2009-12-16 14:02:35 -0500, "Steven Schveighoffer" <schveiguy yahoo.com> said:That sounds correct.On Wed, 16 Dec 2009 09:21:16 -0500, Michel Fortin <michel.fortin michelf.com> wrote:If you're trying to define a ruke it's simple: you can cast immutable to const only on the first level of indirection, or when there is no indirection. So basically those conversions should be allowed: immutable(MyStruct)*[] -> const(MyStruct*)[] immutable(MyStruct*)[] -> const(MyStruct*)[] immutable(MyStruct*[]) -> const(MyStruct*[])Here's what I meant: void doSomething(inout(MyStruct)*[] a, inout(MyStruct)*[] b) { a[0] = b[0]; // works only when structs in both arrays have the same constness. }This is dangerous. We should figure out a reason why this shouldn't compile. It's hard for me to wrap my head around it. Either the implicit cast when calling the function shouldn't work, or the assignment shouldn't work. My intuition is that the implicit cast should fail.I did some testing too. This compiles, which should be a bug: import std.stdio; void myfunc(const(int)[][]a, const(int)[][]b) { a[0]= b[0]; } void main() { immutable(int)[][] i1; i1.length = 1; int [][]i2; i2 ~= [5]; myfunc(i1, i2); writefln("%d", i1[0][0]); i2[0][0] = 6; writefln("%d", i1[0][0]); } Writes: 5 6 I think it has something to do with array casting rules. Because you can cast just the pointer part of the array struct, it appears that these cases aren't considered the same as the pointer casting as you demonstrated. I'll look for a bug on this, and if not, I'll add one. -SteveDoes this code compile today? If so, we need to fix this. With this fixed, the inout version naturally becomes invalid.Just did a couple of small tests. Apparently everything is all right: test.d(18): Error: cannot implicitly convert expression (a) of type immutable(int)*[] to const(int)*[] Also: test.d(18): Error: cannot implicitly convert expression (b) of type int*[] to const(int)*[] Which is right otherwise you could assign immutable values to the array others see as mutable. Also, converting from immutable(int)*[] to const(int*)[] implicitly works fine and does prevent dangerous assignments. So I don't think there is anything to fix on this front.
Dec 16 2009
On Wed, 16 Dec 2009 15:38:56 -0500, Steven Schveighoffer <schveiguy yahoo.com> wrote:I'll look for a bug on this, and if not, I'll add one.2544 (http://d.puremagic.com/issues/show_bug.cgi?id=2544) is a bug that exactly describes this problem, but it was marked as a duplicate of a more general problem in bug 2095 (http://d.puremagic.com/issues/show_bug.cgi?id=2095) apparently, 2095 is a duplicate of a very old bug 926 (http://d.puremagic.com/issues/show_bug.cgi?id=926) I think it's about time this was addressed, especially in the face of allowing unsafe operations in safe D. -Steve
Dec 16 2009
Denis Koroskin Wrote:Yes, one more level of indirection is needed: void doSomething(inout(T)[][] a, inout(T)[][] b){ a[0]=b[0]; } though it's subject to the const bug when you pass T[][] and immutable(T)[][] which is due to the current const system.void doSomething(inout(Object)[] a, inout(Object)[] b) { a[0] = b[0]; // works only when objects in both arrays have the same constness. }Doesn't work. doSomething("hello", "world");
Dec 16 2009
Kagamin wrote:Yes, one more level of indirection is needed: void doSomething(inout(T)[][] a, inout(T)[][] b){ a[0]=b[0]; } though it's subject to the const bug when you pass T[][] and immutable(T)[][] which is due to the current const system.Is this in bugzilla?
Dec 16 2009
On Wed, 16 Dec 2009 13:59:36 -0500, Walter Bright <newshound1 digitalmars.com> wrote:Kagamin wrote:See my post in another part of this thread, there are 3 related bugs in bugzilla. -SteveYes, one more level of indirection is needed: void doSomething(inout(T)[][] a, inout(T)[][] b){ a[0]=b[0]; } though it's subject to the const bug when you pass T[][] and immutable(T)[][] which is due to the current const system.Is this in bugzilla?
Dec 16 2009
Steven Schveighoffer wrote:On Wed, 16 Dec 2009 13:59:36 -0500, Walter Bright <newshound1 digitalmars.com> wrote:Those all looked possibly different, so I put it in as: http://d.puremagic.com/issues/show_bug.cgi?id=3621Kagamin wrote:See my post in another part of this thread, there are 3 related bugs in bugzilla. -SteveYes, one more level of indirection is needed: void doSomething(inout(T)[][] a, inout(T)[][] b){ a[0]=b[0]; } though it's subject to the const bug when you pass T[][] and immutable(T)[][] which is due to the current const system.Is this in bugzilla?
Dec 16 2009
Walter Bright Wrote:Andrei Alexandrescu wrote:I initially liked return as the keyword as well, but it's problematic for intermediate variables. inout(U) foo(inout(T) t){ inout V v = t.someMember.somethingElse; return bar(v); }Time has come to make a decision on implementing Steven Schveighoffer's proposal:Unmentioned in the proposal is is inout a type constructor or a storage class? For example, U[inout(T)]* foo(inout(X)*** p) { ... } This is much more complex to implement than only allowing inout at the top level, i.e. as a storage class. I also prefer the idea of inout on the return type being assumed, rather than explicit: T foo(inout U p) { ... } Yes, there's the legacy compatibility issue there. A long time ago, I suggested using the keyword 'return' for that, instead of inout: T foo(return U p) { ... } which looks fine until you use it for member functions: T foo() return { ... } ugh.
Dec 16 2009
Andrei Alexandrescu, el 15 de diciembre a las 19:02 me escribiste:Time has come to make a decision on implementing Steven Schveighoffer's proposal: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP2 It's been in the back of my mind for a while now, I don't find a fault with it, it solves a very unpleasant problem that would seriously mar qualifiers, and although it doesn't solve 100% of the potential cases, it does solve a good fraction of them. I am confident that we can require body duplication for the remaining stragglers with a straight face. My main concern is allowing shared to participate to the inout transportation. I am tempted to allow it, but shared is constrained much more severely than the other two. To avoid problems with the existing uses of inout (which is an old synonym for ref), the language requires that you redundantly use inout in the return type as well. We could eliminate that in D3. Any thoughts would be appreciated.Looks like inout won: http://www.dsource.org/projects/phobos/changeset/1389 Doesn't look like a very intuitive name though (another enum? :). -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Es más probable que el tomate sea perita, a que la pera tomatito. -- Peperino Pómoro
Dec 18 2009
On Fri, 18 Dec 2009 22:18:36 -0500, Leandro Lucarella <llucax gmail.com> wrote:Looks like inout won: http://www.dsource.org/projects/phobos/changeset/1389 Doesn't look like a very intuitive name though (another enum? :).Better than not having the feature :) Some notes on the to-be description: There is no mention that inout variables cannot be changed (they cannot). In the paragraph describing what inout resolves to on return, if all matches are inout, then the return type should be set to inout, not const. This is important for calling inout functions from within inout functions. I'm really excited to finally see this coming to fruition! Thanks Walter and Andrei! -Steve
Dec 18 2009
Steven Schveighoffer wrote:On Fri, 18 Dec 2009 22:18:36 -0500, Leandro Lucarella <llucax gmail.com> wrote:Thank you for your detailed inout proposal and for making us understand the details of what it takes to define inout. AndreiLooks like inout won: http://www.dsource.org/projects/phobos/changeset/1389 Doesn't look like a very intuitive name though (another enum? :).Better than not having the feature :) Some notes on the to-be description: There is no mention that inout variables cannot be changed (they cannot). In the paragraph describing what inout resolves to on return, if all matches are inout, then the return type should be set to inout, not const. This is important for calling inout functions from within inout functions. I'm really excited to finally see this coming to fruition! Thanks Walter and Andrei!
Dec 19 2009
Steven Schveighoffer Wrote:On Fri, 18 Dec 2009 22:18:36 -0500, Leandro Lucarella <llucax gmail.com> wrote:The docs should also discuss inout variables declared within the function (to store intermediate results while processing input arguments). The meaning of inout by a nested function isn't obvious when the enclosing function is already using inout. Does inout of the nested function match that of the enclosing function? Or are they distinct. If distinct, there may semantically ambiguous cases...Looks like inout won: http://www.dsource.org/projects/phobos/changeset/1389 Doesn't look like a very intuitive name though (another enum? :).Better than not having the feature :) Some notes on the to-be description: There is no mention that inout variables cannot be changed (they cannot). In the paragraph describing what inout resolves to on return, if all matches are inout, then the return type should be set to inout, not const. This is important for calling inout functions from within inout functions. I'm really excited to finally see this coming to fruition! Thanks Walter and Andrei! -Steve
Dec 19 2009
On Sat, 19 Dec 2009 18:35:13 -0500, Jason House <jason.james.house gmail.com> wrote:The docs should also discuss inout variables declared within the function (to store intermediate results while processing input arguments).Yes, good point. Also important is that inout can ONLY be used on stack variables, it can never be used in global or class member variables.The meaning of inout by a nested function isn't obvious when the enclosing function is already using inout. Does inout of the nested function match that of the enclosing function? Or are they distinct. If distinct, there may semantically ambiguous cases...One thing that inout does is it makes the function not really have to care what the calling 'const match' is, because the compiler takes care of that detail at the call site. So the compiled function isn't any different depending on the const match, just the meaning of the return value is different. Here is an example: class Foo { private Bar b; property inout(Bar) bee() inout { return b; } } class Baz { private Foo f; property inout(Bar) getBOfFoo() inout { inout(Bar) b = f.bee; // the 'const match' is inout, because at this point f is inout. return b; } } Notice that when compiling getBOfFoo, the compiler doesn't have to care what inout(Bar) means in order to call f.bee, it just knows that because f is inout, the const match is inout. It's not like it needs to recompile Foo.bee with a new const match, it just allows the result to be implicitly cast to inout. As long as the rules are followed, it doesn't have to be complicated. It's like a template, but where all the instantiations are identical, just the semantic meaning of the return is parameterized. The rules are carefully designed to make the implementation simple and intuitive, but allow precise const protection where it is needed. Another example, showing 2 different types of inout with a nested call: inout(char)[] trim(inout(char)[] input) { while(input.length != 0 && isspace(input[0])) input = input[1..$]; while(input.length != 0 && isspace(input[$-1])) input = input[0..$-1]; return input; } inout(char)[][] split(inout(char)[] src, const(char)[] delimiter) { delimiter = trim(delimiter); // const match for this one call is const, so it's valid to reassign back to const. // inout(char)[] d = trim(delimiter); // illegal, because the const match is const, and const does not implicitly cast to inout. int i; inout(char)[][] result; while((i = src.indexOf(delimiter)) != src.length) { result ~= src[0..i]; src = src[i + delimiter.length..$]; } result ~= src; return result; } Now, split can be called with a mutable, const, immutable, or even inout src, and it doesn't alter your contract on src's data :) The signature says "src is whatever you want it to be, the constancy will be forwarded to the return value, and I promise not to molest src's data. delimiter will not be molested, but its constancy will not play a part in the return value." The cool part about it is that it just works the way you want it to, and provides the protection you want it to. It gives you const protection without the viral nature of const that people dislike. -Steve
Dec 19 2009
Steven Schveighoffer Wrote:On Sat, 19 Dec 2009 18:35:13 -0500, Jason House <jason.james.house gmail.com> wrote:I meant functions nested inside of functions. inout(A) foo(inout B b, inout C c){ inout(D) bar(inout E e, inout F f){ ... } ... }The meaning of inout by a nested function isn't obvious when the enclosing function is already using inout. Does inout of the nested function match that of the enclosing function? Or are they distinct. If distinct, there may semantically ambiguous cases...One thing that inout does is [snip of very long, but off topic reply :(]
Dec 20 2009
On Sun, 20 Dec 2009 07:58:06 -0500, Jason House <jason.james.house gmail.com> wrote:Steven Schveighoffer Wrote:OK, I get what you are saying now, sorry for the off-topic reply. That would pose a confusing prospect. Since we only have one inout keyword, we cannot allow 2 meanings for it. So either we have to disallow inout functions as nested functions, or color the inout portions of the outer function as const implicitly while inside the inner function. I think the most useful choice is the latter. If you want any of the inout variables of the outer function to participate in choosing the inout constancy of the inner function, then they must be explicitly passed. Thanks for clarifying, that is an important thing to get right. -SteveOn Sat, 19 Dec 2009 18:35:13 -0500, Jason House <jason.james.house gmail.com> wrote:I meant functions nested inside of functions. inout(A) foo(inout B b, inout C c){ inout(D) bar(inout E e, inout F f){ ... } ... }The meaning of inout by a nested function isn't obvious when the enclosing function is already using inout. Does inout of the nested function match that of the enclosing function? Or are they distinct.Ifdistinct, there may semantically ambiguous cases...One thing that inout does is [snip of very long, but off topic reply :(]
Dec 20 2009